我在公司帐户上有一个API密钥,并启用了所有相关API,包括适用于iOS的Google Maps API,Google Places和Geocoding/Reverse Geocoding。
API密钥是正确的,我仔细检查了三重检查。
此解决方案在安卓上完美运行。 但是,在iOS上,这段代码完全...即使设置超时也不起作用,对 GetAsync 的函数调用永远不会返回。
这是一个 Xamarin.Forms 项目,此代码在主 PCL 中执行。
这是怎么回事?
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Plugin.Geolocator;
using System.Net.Http;
using MyApp.Models;
using Newtonsoft.Json;
using MyApp.Localization.Resources;
using System.Threading;
using DataTools.Text;
using Plugin.Geolocator.Abstractions;
namespace MyApp.Helpers
{
public class PlacesHelperConfig
{
public Position Position { get; set; }
public int Pages { get; set; } = 1;
public bool SuppressErrors { get; set; } = false;
public string Keyword { get; set; }
public string PlaceType { get; set; } = "restaurant";
public double Radius { get; set; } = 1000;
public bool RankByDistance { get; set; } = false;
}
public class PlacesHelper
{
private CancellationTokenSource cts = new CancellationTokenSource();
public void Cancel()
{
cts.Cancel();
}
public async Task<List<MapPlace>> GetNearbyPlacesAsync(PlacesHelperConfig config)
{
return await GetNearbyPlacesAsync(config.Keyword, config.PlaceType, config.Position, config.Radius, config.RankByDistance, config.Pages, config.SuppressErrors);
}
public async Task<List<MapPlace>> GetNearbyPlacesAsync(string keyword, string placetype, Position position, double radius, bool byDistance, int pages, bool suppressErrors)
{
var places = new List<MapPlace>();
var url = "https://maps.googleapis.com/maps/api/place/nearbysearch/json";
string useUrl = null;
string sJson = null;
try
{
if (!Plugin.Connectivity.CrossConnectivity.Current.IsConnected)
{
if (!suppressErrors) Acr.UserDialogs.UserDialogs.Instance.Alert(AppResources.ErrorNoInternet, "", AppResources.OK);
return null;
}
//var locator = CrossGeolocator.Current;
HttpResponseMessage resp;
if (position == null)
{
throw new ArgumentNullException("Must provide a position");
}
var cli = new HttpClient();
string reqStr = "";
if (!string.IsNullOrEmpty(keyword))
{
reqStr += "keyword=" + TextTools.UrlEncode(keyword);
}
if (!string.IsNullOrEmpty(placetype))
{
if (reqStr != "") reqStr += "&";
reqStr += "type=" + TextTools.UrlEncode(placetype);
}
if (reqStr == "") throw new ArgumentNullException("Must have at least a type or a keyword");
if (byDistance) {
reqStr += "&fields=photos,formatted_address,name,opening_hours,rating&location={0},{1}&key={2}&rankby=distance";
reqStr = string.Format(reqStr, position.Latitude, position.Longitude, ((App)App.Current).MapsApiKey);
}
else
{
reqStr += "&fields=photos,formatted_address,name,opening_hours,rating&radius={0}&location={1},{2}&key={3}";
reqStr = string.Format(reqStr, radius, position.Latitude, position.Longitude, ((App)App.Current).MapsApiKey);
}
MapPlaceQueryReturn returned;
url += "?" + reqStr;
useUrl = url;
var uri = new Uri(useUrl);
cli.Timeout = new TimeSpan(0, 0, 10);
for (int i = 0; i < pages; i++)
{
try
{
resp = await cli.GetAsync(uri, cts.Token);
}
catch
{
if (!suppressErrors) Acr.UserDialogs.UserDialogs.Instance.Alert(AppResources.ErrorNoServer, "", AppResources.OK);
if (places.Count > 0) return places;
else return null;
}
sJson = await resp.Content.ReadAsStringAsync();
returned = JsonConvert.DeserializeObject<MapPlaceQueryReturn>(sJson);
places.AddRange(returned.Results);
if (returned.NextPageToken == null)
break;
else if (pages > 1)
useUrl = url + "&pagetoken=" + returned.NextPageToken;
}
return places;
}
catch
{
if (places.Count > 0) return places;
else return null;
}
}
}
public class MapPlaceQueryReturn
{
[JsonProperty("html_attributions")]
public string[] HtmlAttributions { get; set; }
[JsonProperty("next_page_token")]
public string NextPageToken { get; set; }
[JsonProperty("results")]
public List<MapPlace> Results { get; set; }
}
public class MapPlace
{
[JsonProperty("place_id")]
public string PlaceId { get; set; }
[JsonProperty("geometry")]
public PlaceGeometry Geometry { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("vicinity")]
public string Address { get; set; }
[JsonProperty("types")]
public string[] Types { get; set; }
[JsonProperty("price_level")]
public double PriceLevel { get; set; }
[JsonProperty("rating")]
public double Rating { get; set; }
public override string ToString() => $"{Name},{Address}";
public override bool Equals(object obj) => (obj is MapPlace p && p.PlaceId == PlaceId);
public override int GetHashCode() => (int)Crc32.Calculate(Encoding.UTF8.GetBytes(ToString()));
}
public class PlaceGeometry
{
[JsonProperty("location")]
public PlaceLocation Location { get; set; }
[JsonProperty("viewport")]
public PlaceViewport Viewport { get; set; }
public override string ToString()
{
return $"{Location.Latitude},{Location.Longitude}";
}
}
public class PlaceLocation
{
[JsonProperty("lat")]
public double Latitude { get; set; }
[JsonProperty("lng")]
public double Longitude { get; set; }
public override string ToString()
{
return $"{Latitude},{Longitude}";
}
public PlaceLocation() { }
public PlaceLocation(double latitude, double longitude)
{
Latitude = latitude;
Longitude = longitude;
}
public static implicit operator PlaceLocation(Xamarin.Forms.Maps.Position value)
{
return new PlaceLocation(value.Latitude, value.Longitude);
}
public static implicit operator Xamarin.Forms.Maps.Position(PlaceLocation value)
{
return new Xamarin.Forms.Maps.Position(value.Latitude, value.Longitude);
}
}
public class PlaceViewport
{
[JsonProperty("northeast")]
public PlaceLocation Northeast { get; set; }
[JsonProperty("southwest")]
public PlaceLocation Southwest { get; set; }
}
}
我修复了它。发生的情况是,虽然此代码位于 PCL 代码中,但调用它的代码位于特定于平台的代码中。我创建了一些接口并触发了一些事件,这些事件使PCL代码运行此代码,并且它起作用了。
我不知道它为什么有效...但它奏效了。