I'm using the Uber-SDK for an iOS app. Over the last few days, I can get the cheapest product with ridesClient.fetchCheapestProduct(). But today, that function always returns a nil value.
Is this a problem with the server or SDK? Please help me with this issue.
(I'm in Vietnam and my client_id still works fine for Android)
This is my code:
let ridesClient = RidesClient()
let button = RideRequestButton()
override func viewDidLoad() {
super.viewDidLoad()
let pickupLocation = CLLocation(latitude: 37.775159, longitude: -122.417907)
let dropoffLocation = CLLocation(latitude: 37.6213129, longitude: -122.3789554)
//make sure that the pickupLocation and dropoffLocation is set in the Deeplink
var builder = RideParametersBuilder()
.setPickupLocation(pickupLocation)
// nickname or address is required to properly display destination on the Uber App
.setDropoffLocation(dropoffLocation, nickname: "San Francisco International Airport")
// use the same pickupLocation to get the estimate
ridesClient.fetchCheapestProduct(pickupLocation: pickupLocation, completion: { product, response in
if let productID = product?.productID { //check if the productID exists
builder = builder.setProductID(productID)
self.button.rideParameters = builder.build()
// show estimate in the button
self.button.loadRideInformation()
}
})
// center the button (optional)
button.center = view.center
//put the button in the view
view.addSubview(button)
}
Make sure you set a server token in your Info.plist. This allows the RidesClient() to make a price estimate API call.
Copy this snippet into your Info.plist (right click and select Open As > Source Code) and replace YOUR_SERVER_TOKEN with the Server Token from your dashboard (make sure you use the server token corresponding to your client ID).
<key>UberServerToken</key>
<string>YOUR_SERVER_TOKEN</string>
Related
I'm relatively new to iOS and Mapbox development. I'm working on an app where a user can freely manipulate a map full of places they have saved.
When they reach a zoom-level that is completely filled by the geography of a city, I would like to display the name of the city which they are viewing in a banner-style view, even if a city label is not within view on the map (as is often the case when zoomed in).
Here's a screenshot of the UI for context.
I'm trying to query the Mapbox tileset for the city name using the following code:
func mapViewRegionIsChanging(_ mapView: MGLMapView) {
let zoomLevel = mapView.zoomLevel
if zoomLevel >= 14.0 {
// layer identifier taken from layer name in Mapbox Studio
let layerIdentifier = "place-city-lg-n"
let screenRect = UIScreen.main.bounds
let cityName = mapView.visibleFeatures(in: screenRect, styleLayerIdentifiers: Set([layerIdentifier]))
print(cityName)
}
I think this code doesn't work because the label is not onscreen at the specified zoom level.
I'm wondering if using visibleFeaturesInRect is the best approach for my needโis there a better way to retrieve city name regardless of visible elements and zoom level?
For this task I'd recommend using MapboxGeocoder from Mapbox. It is for getting information about the city/village.
you can install pod:
pod 'MapboxGeocoder.swift', '~> 0.12'
and use this code:
let geocoder = Geocoder.shared
func mapViewRegionIsChanging(_ mapView: MGLMapView) {
let geocodeOptions = ReverseGeocodeOptions(coordinate: mapView.centerCoordinate)
geocodeOptions.allowedScopes = [.place]
let _ = geocoder.geocode(geocodeOptions) { (placemarks, attribution, error) in
guard let placemark = placemarks?.first else { return }
print(placemark.name)
print(placemark.qualifiedName)
}
}
you can add your conditions and it really helps to solve your task
This is my first time using Uber api. I followed the instructions clearly, but it never really mentioned how to display price estimate in the button. My code magically displays the time( dunno why or how). Please explain how to display price as well. Both server token and client ID have been integrated in the info.plist file.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = RideRequestButton()
view.addSubview(button)
button.center = view.center
let ridesClient = RidesClient()
let dropOffLocation = CLLocation(latitude: 20.301647, longitude: 85.819135)
let pickUpLocation = CLLocation(latitude : 20.323706, longitude: 85.814981)
let builder = RideParametersBuilder()
builder.pickupLocation = pickUpLocation
builder.pickupNickname = "Home"
builder.dropoffLocation = dropOffLocation
builder.dropoffNickname = "Mayfair Lagoon, Bhubaneswar"
var productID = ""
ridesClient.fetchProducts(pickupLocation: pickUpLocation) { (product, response) in
productID = product[1].productID
print("๐ฅ\(productID)")
}
ridesClient.fetchPriceEstimates(pickupLocation: pickUpLocation, dropoffLocation: dropOffLocation) { (price, response) in
print(price[0].estimate!,"๐")
}
ridesClient.fetchTimeEstimates(pickupLocation: pickUpLocation) { (time, response) in
print("๐ฅ",time[0].estimate,"๐ฅ")
}
builder.productID = productID
button.setContent()
button.rideParameters = builder.build()
button.loadRideInformation()
}
}
Button will Deeplink into the Uber App and will simply open up the app. In order to see real-time fare estimates and pickup ETA information you will need to pass additional parameters to it. The Ride Request Button can accept optional parameters to pre-load some information into the ride request. You can see how to do it in the Uber documentation. Also this is explained here on the GitHub
Please, check out StackOverflow thread here.
It is explained and documented how to manage this issue.
Please check it out below link
Display ETA and estimated money option for my "Ride there with Uber" button
I posted this issue on GitHub, though it has been over a week and no response from the developers, so hoping to get an answer here.
Using the example code, plus adding a bit to show placemarks returned from ForwardGeocodeOptions, I came up with this testing code:
(Swift 3, Xcode 8)
func mapView(_ mapView: MGLMapView, regionDidChangeAnimated animated: Bool) {
geocodingDataTask?.cancel()
self.outputText.text = ""
// Variables.userLat and Variables.userLng are set through locationManager
let options = ReverseGeocodeOptions(coordinate: CLLocationCoordinate2D(latitude: Variables.userLat, longitude: Variables.userLng))
geocodingDataTask = geocoder.geocode(options) { [unowned self] (placemarks, attribution, error) in
if let error = error {
NSLog("%#", error)
} else if let placemarks = placemarks, !placemarks.isEmpty {
self.resultsLabel.text = placemarks[0].qualifiedName
let foptions = ForwardGeocodeOptions(query: self.inputText.text!)
// To refine the search, you can set various properties on the options object.
foptions.allowedISOCountryCodes = ["US"]
foptions.focalLocation = CLLocation(latitude: Variables.userLat, longitude: Variables.userLng)
let neLat = Variables.userLat + 1.0
let neLng = Variables.userLng + 1.0
foptions.allowedRegion?.northEast = CLLocationCoordinate2D(latitude: neLat, longitude: neLng)
let swLat = Variables.userLat - 1.0
let swLng = Variables.userLng - 1.0
foptions.allowedRegion?.southWest = CLLocationCoordinate2D(latitude: swLat, longitude: swLng)
foptions.allowedScopes = [.address, .pointOfInterest]
let _ = geocoder.geocode(foptions) { (placemarks, attribution, error) in
guard let placemark = placemarks?.first else {
return
}
let coordinate = placemark.location.coordinate
print("\(coordinate.latitude), \(coordinate.longitude)")
self.inputLat.text = coordinate.latitude.description
self.inputLng.text = coordinate.longitude.description
var string = ""
for mark in placemarks! {
if string != "" {
string += "\n"
}
string += mark.qualifiedName
}
self.outputText.text = string
}
} else {
self.resultsLabel.text = "No results"
}
}
}
That gives me a mini-app to test out the data that is returned when I change locations in the Xcode Simulator.
screenshot 2017-07-12 13 54 09
As you can see from this shot, I have centered the map in Jenks, OK (a small town just outside of Tulsa, OK - sort of a 'central US' location.)
When searching for a common place in that area ("Walmart" - which is based in nearby Arkansas, so there are plenty of them around), you can see that only 2 'local' Walmart's come back in the search.
Now, let's move to Bentonville, AR - the home of Walmart......
And, we get two top new results, but the others are the same (and much farther away than Tulsa, OK.....)
We found that if we add the town to the first of the search, the results are much better:
(similar results are true for every search we did - various cities around the US and with other 'common places' like Quiznos (similar results as Walmart when in their home town of Denver, CO...)
As you can see from my code, I tried using the allowedRegion?.northEast and southWest (as I understand it, those should set the search area to about 100 miles around the location, though I'm not sure I set that up right), though no difference was found from this setup (i.e., with/without I get the same results).
The only 'better' results were by putting in the town name along with the 'common' one (though, oddly, different results were returned if the town name was before or after the common one - I didn't check exactly, though I think they are 'best' (i.e., locations are all pretty near) from putting the town name after the common one)
What can I do to get better results without having to tell the user to enter the town name (not a very desirable plan! :)
Thank you in advance for tips - the lookup is a key part of the app (not the test stuff shown in the pictures! ) and users expect to pull up several 'nearby' common places (in this case, we would expect to see all 5 results within something like 20 miles - certainly no more than 100 miles away), so it is an important thing for us that this work much more reliably than we are seeing now.
It's quite easy to add an annotation to a MapKit view which is inside your app.
theMap: MKMapView!
let pa = MKPointAnnotation()
pa.title = "title!!" etc
theMap.addAnnotation(pa)
But how the heck do you make the Maps App add an annotation??
Here's exactly how to open the Maps App to a certain address..
func appleMapApp() {
quickAddressText = "123 Smith St 90210"
let bottomText = "This shows at BOTTOM Of Maps App screen."
let g = CLGeocoder()
g.geocodeAddressString(quickAddressText) { placemarks, error in
if let found = placemarks?.first, let lok = found.location {
let p = MKPlacemark(coordinate: lok.coordinate, addressDictionary: nil)
let mapItem = MKMapItem(placemark: p)
mapItem.name = bottomText
mapItem.openInMaps(launchOptions: showing(location: lok))
}
}
}
// convenient function...
func showing(location: CLLocation, meters m: CLLocationDistance = 1000)->[String : Any]? {
let cr = MKCoordinateRegionMakeWithDistance(location.coordinate, m,m)
let options = [
MKLaunchOptionsMapCenterKey: NSValue(mkCoordinate: cr.center),
MKLaunchOptionsMapSpanKey: NSValue(mkCoordinateSpan: cr.span)
]
return options
}
That's great - but how the heck do you pass in a MKPointAnnotation to the actual Maps app??
(Again - it's easy to add a MKPointAnnotation on a map view inside your own app.)
Any ideas? Is it actually possible??
I think openInMaps limits you only to the five possible launch options. But I wonder if you could get Apple Maps to open in the original way, openURL and maps.apple.com/maps, as shown in this SO question. With the newest iOS versions, though, it seems you also need to register the URL you're using in your info.plist under "URL Types ... URL Schemes" or "LSApplicationQueriesSchemes". You might be able to pass an annotation as a parameter with the URL.
I don't know about anyone else, but EventKit seems to have very little in terms resources and tutorials online for you to refer to for help.
I need to trigger an alarm when a user hits a radius of a set of coordinates, I wasn't sure of the best ay to do this, I was torn between local notifications, and EventKit reminders.
I decided to go for eventKit as I felt that I could do more with more the alarms and it was the most practical way to do it however, having not known much about EventKit i had some issues.
Anyway I've managed to get together and build a sample project which works and triggers an alert when the user leaves their current location, the only problem is, is that I almost want to do the complete opposite of that, I want to trigger an alert when the user enters a set of coordinates, I assume that most of the code is transferrable, however I seem to be stuck on one bit mainly.
// Creates an EKStructuredLocation Instance with a title of "Current Location"
let location = EKStructuredLocation(title: "Current Location")
// Uses the last location update extracted from the locations array to supply you're current location
location.geoLocation = locations.last as! CLLocation
// Location is added to a newly created alarm instance
let alarm = EKAlarm()
alarm.structuredLocation = location
// This alarm is triggered when the user moves away from the location proximity
alarm.proximity = EKAlarmProximityLeave
stationReminder.addAlarm(alarm)
I'm struggling to find how to set the location of the alarm to coordinates rather than users location.
I tried changing this
location.geoLocation = locations.last as! CLLocation
to
location.geoLocation = CLCircularRegion(circularRegionWithCenter: CLLocationCoordinate2D(latitude: 37.33233141, longitude: -122.03121860), radius: 50.0, identifier: "Location1")
but this doesn't work, i believe i am on the right track but i am throwing up this error: Cannot assign a value of type 'CLCircularRegion!' to a value of type 'CLLocation!'
I've tried loads of things with no resolve, does anybody have any experience with this and know how to help?
I also assume i'll have to change the following from this
alarm.proximity = EKAlarmProximityLeave
to this
alarm.proximity = EKAlarmProximityEnter
UPDATE
I've taken on board some comments below and tried a bunch of other things to get this to work, I feel like I am so close but somethings just missing. I cannot get this alarm to trigger. Excuse all the code comments, it's just so you can see some of the attempts i have made at fixing this.
can anyone see anything wrong with this code for the alarm?
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
// Stops location manager from sending further updates
locationManager.stopUpdatingLocation()
// Creates a new EKReminder which is named and initialised with text from the UITextField
let stationReminder = EKReminder(eventStore: appDelegate!.eventStore)
stationReminder.title = locationText.text
// Stores the previously created EKReminder in the default calendar
stationReminder.calendar = appDelegate!.eventStore!.defaultCalendarForNewReminders()
// Creates an EKStructuredLocation Instance with a title of "Current Location"
let location = EKStructuredLocation(title: "Destination: Bournemouth Station")
// Uses the last location update extracted from the locations array to supply you're current location
// location.geoLocation = locations.last as! CLLocation
// location.geoLocation = CLCircularRegion(circularRegionWithCenter: CLLocationCoordinate2D(latitude: 37.33233141, longitude: -122.03121860), radius: 50.0, identifier: "Location1")
// location.geoLocation = CLLocation(latitude: 50.742771, longitude: -1.895072)
location.radius = 50.0
location.geoLocation = CLLocation(latitude:50.742771, longitude:-1.895072)
// location.radius = 10.0 // metres
// Location is added to a newly created alarm instance
let alarm = EKAlarm()
alarm.structuredLocation = location
// This alarm is triggered when the user moves away from the location proximity
// alarm.proximity = EKAlarmProximityEnter
alarm.proximity = EKAlarmProximityEnter // "geofence": we alarm when *arriving*
// but this will have no effect until Reminders is granted Location access...
// and in iOS 8 it won't even ask for it until it is launched
// also, in iOS 8 the separate background usage pref is withdrawn;
// instead, auth of Reminders for "when in use" covers this...
// ...because it means "this app *or one of its features* is visible on screen"
stationReminder.addAlarm(alarm)
// Now we have a fully configured reminder which we save in the Event Store
var error: NSError?
appDelegate!.eventStore?.saveReminder(stationReminder,
commit: true, error: &error)
if error != nil {
println("Reminder failed with error \(error?.localizedDescription)")
}
}
Looks like EKEvent has an EKStructuredLocation, which you are using correctly. However, you need to be careful of the type of the geoLocation property. It should be a CLLocation, which is not the same as a CLCircularRegion.
Steps to fix:
check the docs for EKStructuredLocation https://developer.apple.com/library/mac/documentation/EventKit/Reference/EKStructuredLocationClassRef/index.html
set the location.geoLocation to a CLLocation that you create from latitude, longitude coordinates. (check the docs for CLLocation: https://developer.apple.com/library/mac/documentation/CoreLocation/Reference/CLLocation_Class/index.html#//apple_ref/swift/cl/CLLocation)
geoLocation = CLLocation(latitude: 37.33233141, longitude: -122.03121860)
set the geoLocation.radius separately location.radius = 50.0
at that point setting proximityEnter should work as you expected