项目作者: dorisoy

项目描述 :
Xamarin Android binding library for Baidumap sdk(5.3.2/6.4/7.0/7.1)
高级语言: C#
项目地址: git://github.com/dorisoy/BaiduMaps.git
创建时间: 2020-02-05T07:46:34Z
项目社区:https://github.com/dorisoy/BaiduMaps

开源协议:

下载


Xamarin.Forms.BaiduMaps

BaiduMap 地图和定位在Xamarin.Android/Xamarin.Forms 中的应用(5.3.2/6.4/7.0/7.1)

SDK 5.3.2/6.4/7.0/7.1 通用匹配绑定规则:

  1. <metadata>
  2. <attr path="/api/package[@name='com.baidu.mapapi']/class[@name='VersionInfo']/field[@name='VERSION_INFO']"
  3. name="name">VersionInformation</attr>
  4. <attr path="/api/package[@name='com.baidu.location']/class[@name='Address']/field[@name='address']"
  5. name="name">Addresses</attr>
  6. <attr path="/api/package[@name='com.baidu.mapapi.map']/interface[@name='BaiduMap.OnMapStatusChangeListener']/method[@name='onMapStatusChangeStart' and count(parameter)=2 and parameter[1][@type='com.baidu.mapapi.map.MapStatus'] and parameter[2][@type='int']]"
  7. name="managedName">OnMapStatusChangeStart2</attr>
  8. <attr path="/api/package[@name='com.baidu.mapapi.search.poi']/interface[@name='OnGetPoiSearchResultListener']/method[@name='onGetPoiDetailResult' and parameter[1][@type='com.baidu.mapapi.search.poi.PoiDetailSearchResult']]"
  9. name="managedName">OnGetPoiDetailResult2</attr>
  10. <attr path="/api/package[@name='com.baidu.platform.comapi.map']/interface[@name='MapViewListener']/method[@name='onClickedItem' and count(parameter)=4 and parameter[1][@type='int'] and parameter[2][@type='int'] and parameter[3][@type='com.baidu.platform.comapi.basestruct.GeoPoint'] and parameter[4][@type='long']]"
  11. name="managedName">OnClickedItem2</attr>
  12. <attr path="/api/package[@name='com.baidu.platform.comapi.map']/interface[@name='NaviMapViewListener']/method[@name='onMapRenderModeChange' and count(parameter)=1 and parameter[1][@type='int']]"
  13. name="managedName">OnMapRenderModeChange2</attr>
  14. <attr path="/api/package[@name='com.baidu.platform.comapi.map']/interface[@name='NaviMapViewListener']/method[@name='onMapAnimationFinish' and count(parameter)=0]"
  15. name="managedName">OnMapAnimationFinish2</attr>
  16. <attr path="/api/package[@name='com.baidu.platform.comapi.map']/class[@name='ItemizedOverlay']/method[@name='compare' and count(parameter)=2 and parameter[1][@type='java.lang.Integer'] and parameter[2][@type='java.lang.Integer']]"
  17. name="managedType">Java.Lang.Integer</attr>
  18. <add-node path="/api/package/class[implements[@name='java.lang.Comparable']]">
  19. <method name="compareTo"
  20. return="int"
  21. abstract="false"
  22. native="false"
  23. synchronized="false"
  24. static="false"
  25. final="false"
  26. deprecated="not deprecated"
  27. visibility="public">
  28. <parameter name="o"
  29. type="java.lang.Object" />
  30. </method>
  31. </add-node>
  32. <add-node path="/api/package/class[implements[@name='java.util.Comparator']]">
  33. <method name="compare"
  34. return="int"
  35. abstract="false"
  36. native="false"
  37. synchronized="false"
  38. static="false"
  39. final="false"
  40. deprecated="not deprecated"
  41. visibility="public">
  42. <parameter name="o1"
  43. type="java.lang.Object" />
  44. <parameter name="o2"
  45. type="java.lang.Object" />
  46. </method>
  47. </add-node>
  48. </metadata>

如果你使用单独的定位服务,可以使用如下方式:
将定位SDK的SERVICE设置成为前台服务,使用Notification, 提高定位进程存活率

  1. [Activity(Label = "App Name",
  2. Icon = "@mipmap/ic_launcher",
  3. Theme = "@style/MainTheme",
  4. LaunchMode = LaunchMode.SingleTop,
  5. ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
  6. public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
  7. {
  8. private static LocationClient mLocationClient = null;
  9. private MyLocationListener myLocationListener = new MyLocationListener();
  10. private Notification mNotification;
  11. protected override void OnCreate(Bundle bundle)
  12. {
  13. base.OnCreate(bundle);
  14. TabLayoutResource = Resource.Layout.Tabbar;
  15. ToolbarResource = Resource.Layout.Toolbar;
  16. //动态请求用户允许使用定位权限
  17. if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.AccessFineLocation) != Permission.Granted)
  18. {
  19. RequestPermissions(new string[] {
  20. Manifest.Permission.AccessNetworkState,
  21. Manifest.Permission.Internet,
  22. Manifest.Permission.WriteExternalStorage,
  23. Manifest.Permission.ReadExternalStorage,
  24. Manifest.Permission.AccessCoarseLocation,
  25. Manifest.Permission.AccessFineLocation,
  26. Manifest.Permission.AccessWifiState,
  27. Manifest.Permission.WriteSettings }, 1);
  28. }
  29. else
  30. {
  31. InitLocation();
  32. InitNotification();
  33. }
  34. Xamarin.Forms.Forms.Init(this, bundle);
  35. LoadApplication(new App(new AndroidInitializer()));
  36. }
  37. #region BaiduSDK
  38. /// <summary>
  39. /// 初始化配置
  40. /// </summary>
  41. private void InitLocation()
  42. {
  43. // 创建定位客户端
  44. mLocationClient = new LocationClient(this);
  45. myLocationListener = new MyLocationListener();
  46. // 注册定位监听
  47. mLocationClient.RegisterLocationListener(myLocationListener);
  48. LocationClientOption mOption = new LocationClientOption();
  49. //高精度
  50. mOption.SetLocationMode(LocationClientOption.LocationMode.HightAccuracy);
  51. //附近地址
  52. mOption.SetIsNeedAddress(true);
  53. // 可选,默认0,即仅定位一次,设置发起连续定位请求的间隔需要大于等于1000ms才是有效的
  54. mOption.ScanSpan = 1000;
  55. // 可选,默认gcj02,设置返回的定位结果坐标系,如果配合百度地图使用,建议设置为bd09ll;
  56. mOption.CoorType = "bd09ll";
  57. // 可选,默认false,设置是否开启Gps定位
  58. mOption.OpenGps = true;
  59. // 设置定位参数
  60. mLocationClient.LocOption = mOption;
  61. }
  62. /// <summary>
  63. /// 初始化前台服务
  64. /// </summary>
  65. private void InitNotification()
  66. {
  67. //设置后台定位
  68. //android8.0及以上使用NotificationUtils
  69. if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
  70. {
  71. var notificationUtils = new NotificationUtils(this);
  72. var builder = notificationUtils.GetAndroidChannelNotification("MyAPP", "正在后台定位");
  73. mNotification = builder.Build();
  74. }
  75. else
  76. {
  77. //获取一个Notification构造器
  78. Notification.Builder builder = new Notification.Builder(ApplicationContext, NotificationUtils.ANDROID_CHANNEL_ID);
  79. Intent nfIntent = new Intent(this, typeof(MainActivity));
  80. var currenttimemillis = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
  81. builder.SetContentIntent(PendingIntent.GetActivity(this, 0, nfIntent, 0))
  82. .SetContentTitle("定位服务")
  83. .SetSmallIcon(Android.Resource.Mipmap.SymDefAppIcon)
  84. .SetContentText("正在后台定位")
  85. .SetWhen(currenttimemillis);
  86. //获取构建好的Notification
  87. mNotification = builder.Build();
  88. }
  89. }
  90. /// <summary>
  91. /// 定义位置侦听
  92. /// </summary>
  93. private class MyLocationListener : BDAbstractLocationListener
  94. {
  95. public async override void OnReceiveLocation(BDLocation lct)
  96. {
  97. if (lct == null)
  98. return;
  99. try
  100. {
  101. // 此处设置开发者获取到的方向信息,顺时针0-360
  102. var locData = new MyLocationData.Builder()
  103. .Accuracy(lct.Radius)
  104. .Direction(lct.Direction).Latitude(lct.Latitude)
  105. .Longitude(lct.Longitude)
  106. .Build();
  107. var msg = $"OnReceiveLocation:{lct.Latitude} Latitude:{lct.Longitude} Address:{lct.Country}{lct.Province}{lct.City}{lct.Address?.Street}";
  108. Log.Info("获取位置:", msg);
  109. //在这里可以实现你的本地存储
  110. //TODO...
  111. }
  112. catch (Java.Lang.Exception ex)
  113. {
  114. Android.Util.Log.Error("Exception", ex.Message);
  115. }
  116. }
  117. }
  118. #endregion
  119. protected override void OnStart()
  120. {
  121. base.OnStart();
  122. //app 从后台唤醒,进入前台
  123. activityActive++;
  124. isBackground = false;
  125. Android.Util.Log.Info("ACTIVITY", "程序从后台唤醒");
  126. // 将定位SDK的SERVICE设置成为前台服务, 提高定位进程存活率
  127. mLocationClient?.EnableLocInForeground(1, mNotification);
  128. mLocationClient?.Start();
  129. }
  130. protected override void OnStop()
  131. {
  132. activityActive--;
  133. if (activityActive == 0)
  134. {
  135. //app 进入后台
  136. isBackground = true;
  137. //程序进入后台
  138. Android.Util.Log.Info("ACTIVITY", "程序进入后台");
  139. //关闭后台定位(true:通知栏消失;false:通知栏可手动划除)
  140. mLocationClient?.DisableLocInForeground(true);
  141. mLocationClient?.Stop();
  142. }
  143. base.OnStop();
  144. }
  145. protected override void OnDestroy()
  146. {
  147. base.OnDestroy();
  148. // 关闭前台定位服务
  149. mLocationClient?.DisableLocInForeground(true);
  150. //取消之前注册的 BDAbstractLocationListener 定位监听函数
  151. if (myLocationListener != null)
  152. mLocationClient?.UnRegisterLocationListener(myLocationListener);
  153. //停止Baidu定位服务
  154. mLocationClient?.Stop();
  155. }
  156. protected override void OnResume()
  157. {
  158. base.OnResume();
  159. }
  160. protected override void OnNewIntent(Intent intent)
  161. {
  162. base.OnNewIntent(intent);
  163. }
  164. protected override void OnActivityResult(int requestCode, Result resultCode, Intent intent)
  165. {
  166. base.OnActivityResult(requestCode, resultCode, intent);
  167. }
  168. public override void OnWindowFocusChanged(bool hasFocus)
  169. {
  170. base.OnWindowFocusChanged(hasFocus);
  171. base.Window.SetBackgroundDrawable(null);
  172. }
  173. public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
  174. {
  175. base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
  176. Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
  177. }
  178. }

在Xamarin.Forms 中,如果你使用基本地图视图模式,并且在加载地图时开始定位服务,你可以自定义一个MapView,定义一个IBaiduLocationService 接口用来创建位置服务,如下:

  1. public class Map : View
  2. {
  3. public Map()
  4. {
  5. VerticalOptions = HorizontalOptions = LayoutOptions.FillAndExpand;
  6. }
  7. /// <summary>
  8. /// 地图坐标类型
  9. /// </summary>
  10. public static readonly BindableProperty MapTypeProperty = BindableProperty.Create(
  11. propertyName: nameof(MapType),
  12. returnType: typeof(MapType),
  13. declaringType: typeof(Map),
  14. defaultValue: MapType.Standard
  15. );
  16. public MapType MapType
  17. {
  18. get { return (MapType)GetValue(MapTypeProperty); }
  19. set { SetValue(MapTypeProperty, value); }
  20. }
  21. /// <summary>
  22. /// 使用跟踪模式
  23. /// </summary>
  24. public static readonly BindableProperty UserTrackingModeProperty = BindableProperty.Create(
  25. propertyName: nameof(UserTrackingMode),
  26. returnType: typeof(UserTrackingMode),
  27. declaringType: typeof(Map),
  28. defaultValue: UserTrackingMode.None
  29. );
  30. public UserTrackingMode UserTrackingMode
  31. {
  32. get { return (UserTrackingMode)GetValue(UserTrackingModeProperty); }
  33. set { SetValue(UserTrackingModeProperty, value); }
  34. }
  35. /// <summary>
  36. /// 显示用户位置
  37. /// </summary>
  38. public static readonly BindableProperty ShowUserLocationProperty = BindableProperty.Create(
  39. propertyName: nameof(ShowUserLocation),
  40. returnType: typeof(bool),
  41. declaringType: typeof(Map),
  42. defaultValue: true
  43. );
  44. public bool ShowUserLocation
  45. {
  46. get { return (bool)GetValue(ShowUserLocationProperty); }
  47. set { SetValue(ShowUserLocationProperty, value); }
  48. }
  49. /// <summary>
  50. /// 显示指南针
  51. /// </summary>
  52. public static readonly BindableProperty ShowCompassProperty = BindableProperty.Create(
  53. propertyName: nameof(ShowCompass),
  54. returnType: typeof(bool),
  55. declaringType: typeof(Map),
  56. defaultValue: true
  57. );
  58. public bool ShowCompass
  59. {
  60. get { return (bool)GetValue(ShowCompassProperty); }
  61. set { SetValue(ShowCompassProperty, value); }
  62. }
  63. /// <summary>
  64. /// 指南针位置
  65. /// </summary>
  66. public static readonly BindableProperty CompassPositionProperty = BindableProperty.Create(
  67. propertyName: nameof(CompassPosition),
  68. returnType: typeof(Point),
  69. declaringType: typeof(Map),
  70. defaultValue: new Point(40, 40)
  71. );
  72. public Point CompassPosition
  73. {
  74. get { return (Point)GetValue(CompassPositionProperty); }
  75. set { SetValue(CompassPositionProperty, value); }
  76. }
  77. /// <summary>
  78. /// 缩放比例
  79. /// </summary>
  80. public static readonly BindableProperty ZoomLevelProperty = BindableProperty.Create(
  81. propertyName: nameof(ZoomLevel),
  82. returnType: typeof(float),
  83. declaringType: typeof(Map),
  84. defaultValue: 11f
  85. );
  86. public float ZoomLevel
  87. {
  88. get { return (float)GetValue(ZoomLevelProperty); }
  89. set { SetValue(ZoomLevelProperty, value); }
  90. }
  91. /// <summary>
  92. /// 最小缩放比例
  93. /// </summary>
  94. public static readonly BindableProperty MinZoomLevelProperty = BindableProperty.Create(
  95. propertyName: nameof(MinZoomLevel),
  96. returnType: typeof(float),
  97. declaringType: typeof(Map),
  98. defaultValue: 3f
  99. );
  100. public float MinZoomLevel
  101. {
  102. get { return (float)GetValue(MinZoomLevelProperty); }
  103. set { SetValue(MinZoomLevelProperty, value); }
  104. }
  105. /// <summary>
  106. /// 最大缩放比例
  107. /// </summary>
  108. public static readonly BindableProperty MaxZoomLevelProperty = BindableProperty.Create(
  109. propertyName: nameof(MaxZoomLevel),
  110. returnType: typeof(float),
  111. declaringType: typeof(Map),
  112. defaultValue: 22f
  113. );
  114. public float MaxZoomLevel
  115. {
  116. get { return (float)GetValue(MaxZoomLevelProperty); }
  117. set { SetValue(MaxZoomLevelProperty, value); }
  118. }
  119. /// <summary>
  120. /// 中心位置
  121. /// </summary>
  122. public static readonly BindableProperty CenterProperty = BindableProperty.Create(
  123. propertyName: nameof(Center),
  124. returnType: typeof(Coordinate),
  125. declaringType: typeof(Map),
  126. defaultValue: new Coordinate(28.693, 115.958)
  127. );
  128. public Coordinate Center
  129. {
  130. get { return (Coordinate)GetValue(CenterProperty); }
  131. set { SetValue(CenterProperty, value); }
  132. }
  133. /// <summary>
  134. /// 显示缩放工具条
  135. /// </summary>
  136. public static readonly BindableProperty ShowScaleBarProperty = BindableProperty.Create(
  137. propertyName: nameof(ShowScaleBar),
  138. returnType: typeof(bool),
  139. declaringType: typeof(Map),
  140. defaultValue: true
  141. );
  142. public bool ShowScaleBar
  143. {
  144. get { return (bool)GetValue(ShowScaleBarProperty); }
  145. set { SetValue(ShowScaleBarProperty, value); }
  146. }
  147. /// <summary>
  148. /// 清除覆盖物
  149. /// </summary>
  150. public static readonly BindableProperty ClearOverlayProperty = BindableProperty.Create(
  151. propertyName: nameof(ClearOverlay),
  152. returnType: typeof(bool),
  153. declaringType: typeof(Map),
  154. defaultValue: false
  155. );
  156. public bool ClearOverlay
  157. {
  158. get { return (bool)GetValue(ClearOverlayProperty); }
  159. set { SetValue(ClearOverlayProperty, value); }
  160. }
  161. /// <summary>
  162. /// 显示缩放工具栏
  163. /// </summary>
  164. public static readonly BindableProperty ShowZoomControlProperty = BindableProperty.Create(
  165. propertyName: nameof(ShowZoomControl),
  166. returnType: typeof(bool),
  167. declaringType: typeof(Map),
  168. defaultValue: true
  169. );
  170. public bool ShowZoomControl
  171. {
  172. get { return (bool)GetValue(ShowZoomControlProperty); }
  173. set { SetValue(ShowZoomControlProperty, value); }
  174. }
  175. public IBaiduLocationService LocationService { get; set; }
  176. public IProjection Projection { get; set; }
  177. public IList<Pin> Pins => pins;
  178. private readonly ObservableCollection<Pin> pins = new ObservableCollection<Pin>();
  179. public IList<Polyline> Polylines => polylines;
  180. private readonly ObservableCollection<Polyline> polylines = new ObservableCollection<Polyline>();
  181. public IList<Polygon> Polygons => polygons;
  182. private readonly ObservableCollection<Polygon> polygons = new ObservableCollection<Polygon>();
  183. public IList<Circle> Circles => circles;
  184. private readonly ObservableCollection<Circle> circles = new ObservableCollection<Circle>();
  185. public event EventHandler<MapBlankClickedEventArgs> BlankClicked;
  186. public void SendBlankClicked(Coordinate pos)
  187. {
  188. BlankClicked?.Invoke(this, new MapBlankClickedEventArgs(pos));
  189. }
  190. public event EventHandler<MapPoiClickedEventArgs> PoiClicked;
  191. public void SendPoiClicked(Poi poi)
  192. {
  193. PoiClicked?.Invoke(this, new MapPoiClickedEventArgs(poi));
  194. }
  195. public event EventHandler<MapDoubleClickedEventArgs> DoubleClicked;
  196. public void SendDoubleClicked(Coordinate pos)
  197. {
  198. DoubleClicked?.Invoke(this, new MapDoubleClickedEventArgs(pos));
  199. }
  200. public event EventHandler<MapLongClickedEventArgs> LongClicked;
  201. public void SendLongClicked(Coordinate pos)
  202. {
  203. LongClicked?.Invoke(this, new MapLongClickedEventArgs(pos));
  204. }
  205. public event EventHandler<EventArgs> Loaded;
  206. public void SendLoaded()
  207. {
  208. Loaded?.Invoke(this, EventArgs.Empty);
  209. }
  210. public event EventHandler<EventArgs> StatusChanged;
  211. public void SendStatusChanged()
  212. {
  213. StatusChanged?.Invoke(this, EventArgs.Empty);
  214. }
  215. }

在你的Android项目中 定义一个MapRenderer,继承自 ViewRenderer
在 OnElementChanged(ElementChangedEventArgs e) 中实现你的的接口 IBaiduLocationService

例如:

  1. protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
  2. {
  3. base.OnElementChanged(e);
  4. if (null == Control)
  5. {
  6. SetNativeControl(new MapView(Context));
  7. }
  8. if (null != e.OldElement)
  9. {
  10. var oldMap = e.OldElement;
  11. ((BaiduLocationServiceImpl)oldMap.LocationService).Unregister();
  12. MapView oldMapView = Control;
  13. oldMapView.OnDestroy();
  14. }
  15. if (null != e.NewElement)
  16. {
  17. Map.LocationService = new BaiduLocationServiceImpl(NativeMap, Context);
  18. }
  19. }

在你的Xaml视图中启动或者停止服务:

  1. protected override void OnAppearing()
  2. {
  3. try
  4. {
  5. base.OnAppearing();
  6. //启动服务
  7. map.LocationService?.Start();
  8. }
  9. catch (Exception ex)
  10. {
  11. Log.Write(ex);
  12. }
  13. }
  14. protected override void OnDisappearing()
  15. {
  16. try
  17. {
  18. base.OnDisappearing();
  19. //停止服务
  20. map.LocationService?.Stop();
  21. }
  22. catch (Exception ex)
  23. {
  24. Log.Write(ex);
  25. }
  26. }

你也可以把SDK进程捆绑在主进程中,去掉 android:process=”:remote”,
然后把 LocationClientOption 的 ScanSpan 设置为0,默认0,即仅定位一次,然后自定义一个Service
在服务里定义频率执行间隔定位,当然,你可以使用WorkManager,使用PeriodicWorkRequest 定义一个Worker间隔定位, 例如:

  1. <service android:name="com.baidu.location.f"
  2. android:enabled="true"
  3. android:foregroundServiceType="location" ></service>
  1. [Service]
  2. public class LocationService : Service
  3. {
  4. CancellationTokenSource _cts;
  5. public override IBinder OnBind(Intent intent)
  6. {
  7. return null;
  8. }
  9. public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
  10. {
  11. _cts = new CancellationTokenSource();
  12. Task.Run(async () =>
  13. {
  14. Location locShared = null;
  15. try
  16. {
  17. locShared = new Location();
  18. await locShared.Run(_cts.Token);
  19. }
  20. catch (Android.OS.OperationCanceledException)
  21. {
  22. }
  23. finally
  24. {
  25. if (_cts.IsCancellationRequested)
  26. {
  27. var message = new StopServiceMessage();
  28. Device.BeginInvokeOnMainThread(() => MessagingCenter.Send(message, "ServiceStopped")
  29. );
  30. }
  31. }
  32. }, _cts.Token);
  33. return StartCommandResult.Sticky;
  34. }
  35. public override void OnDestroy()
  36. {
  37. if (_cts != null)
  38. {
  39. _cts.Token.ThrowIfCancellationRequested();
  40. _cts.Cancel();
  41. }
  42. base.OnDestroy();
  43. }
  44. }
  45. public class Location
  46. {
  47. readonly bool stopping = false;
  48. public Location()
  49. {
  50. try
  51. {
  52. //
  53. }
  54. catch (Java.Lang.Exception ex)
  55. {
  56. Android.Util.Log.Error("上报", ex.Message);
  57. }
  58. }
  59. public async Task Run(CancellationToken token)
  60. {
  61. await Task.Run(async () =>
  62. {
  63. while (!stopping)
  64. {
  65. token.ThrowIfCancellationRequested();
  66. try
  67. {
  68. await Task.Delay(2000);
  69. System.Diagnostics.Debug.Print($"间隔2秒GPS定位一次.....");
  70. var request = new GeolocationRequest(GeolocationAccuracy.Best);
  71. var location = await Geolocation.GetLocationAsync(request);
  72. if (location != null)
  73. {
  74. GlobalSettings.Latitude = location.Latitude;
  75. GlobalSettings.Longitude = location.Longitude;
  76. System.Diagnostics.Debug.Print($"{location.Latitude} {location.Longitude}");
  77. }
  78. }
  79. catch (Exception)
  80. {
  81. Device.BeginInvokeOnMainThread(() =>
  82. {
  83. var errormessage = new LocationErrorMessage();
  84. MessagingCenter.Send(errormessage, "LocationError");
  85. });
  86. }
  87. }
  88. }, token);
  89. }
  90. }

Screenshot