i'm new user here, but I have used stackoverflow a lot of times :)... I'm android developer, but now i'm working in an ios app using swift. I'm totally new using xcode, maybe my question es very simple for a lot... Great, I really need help.
I'm trying to implement a backgroud task that updates the user location each ten minutes. I need to get the lat and long data and after send this info to an API web service. I have been rading the backgroud docs, all documentation, and all the documentation about user location services. There is a lot of information, pretty information, but, maybe i'm very wonted to the android information, with s lot of information too, but a lot of easy examples also, then, is very easy for me. and an previous stackoverflow questionmaybe helpme a lot.
I understand a lot of concepts, and I cofigured my info.plist like the documentation says, but... how can I run a background task for get the user location? Where I must write the background task code? What is the beginning? I have a project with three diferent viewcontrollers and I need to start the service with a button... Thank you so much, I really need to understand the start point of all this.
I am currently doing kind of the same thing as my first iOS-project - what helped me was this :
Periodic iOS background location updates
And from there on I found a Swift-Port of https://github.com/voyage11/Location: https://github.com/silento/Location. In the project from voyage11, there is also linked a blog post that a bit of clarifies what is happening and that also links to a second one that tells how to restart location services using "significant location changes". I am currently trying to implement this with "region location monitoring", but not sure if it will work.
Oh, and I moved the code that triggers a new background task out of the didUpdateLocation-part to the restartLocationUpdates-part - so you can be sure your task is restarted even if you do not get a location in time.
It did not work from the start, but when I added the code from https://stackoverflow.com/a/19085518/3085985 as a replacement for the stopUpdatingLocation() and startUpdatingLocation() - parts.
It is really more complicated than it should be and what I am used from Android - but it is how it is. If you are developing for Iphone5+ you can also consider this post (I could not test it right now as I only have an iPhone 4S and the feature is not supported in the Simulator): https://stackoverflow.com/a/24666487/3085985.
I hope you got some starting points, I am currently still testing my solution but it seems to work as far as I can see now ;)
P.S.: I somewhere read something about background tasks sleeping for more than 5 minutes being canceled - as I only wait 30 seconds I do not have this issue, but you might have. But maybe keeping location services running with a really high distance prevents this from happening.
P.P.S.: As Swift is new you should get used to reading Objective C-Code and trying to translate it to Swift. It often is the only way to find good tutorials.
One more thing - for iOS8 you need something like :
if (self.locationManager.respondsToSelector(Selector("requestWhenInUseAuthorization"))) {
// on iOS8+, we need to request the location authorization ourselves -.-
self.locationManager.requestAlwaysAuthorization()
}
And don't forget to add the "NSLocationAlwaysUsageDescription" to your Info.plist as well as allowing background location updates in your project capabilities.
Sorry for this mess of text, but it is a really complicated topic ;)
edit: Regarding your first comment :
You should create a Swift project, e.g. with a single window and in Main. storyboard add a switch. Then you should implement a ToggleActionChanged-event enabling or disabling the listeners, depending on the new state of the switch. I cannot explain all the basics, you should watch a basic tutorial, I like https://www.youtube.com/playlist?list=PL_4rJ_acBNMHa_RGZigG2nQI3aL1kTa4r and used especially the 7th video as an example of how to build a basic app. The only thing that can be made easier than shown there is using right-click-dragging from the storyboard to the code view instead of implementing some methods by hand. There is a handy assistant.
For your location event listeners you can add a new swift class and name it e.g. LocationDelegate.swift . It makes it a bit more clean. I use a Singleton-pattern for that, you can look up how to do this. Or you could use the structure of the github-project I posted above. I can't provide the complete source as you need to change it so it fits your individual needs ;)
Oh, and one more thing : To remember if your switch is enabled between application launches, you can use something like this :
#IBAction func toggleTrackingChanged(sender: UISwitch) {
// This is your method for when the switch changed... put your location activation/deactivation here
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setBool(sender.on, forKey: "ODLTrackingActive")
}
}
and in your viewDidLoad-Method :
let userDefaults = NSUserDefaults.standardUserDefaults()
var trackingActive = userDefaults.boolForKey("ODLTrackingActive")
toggleTrackingSwitch.setOn(trackingActive, animated: false)
// reactivate location tracking if necessary
Good luck!
Related
This question already has an answer here:
Update location in Background
(1 answer)
Closed 4 years ago.
I'm making a location tracking app. In this app, I need to record user location every 10 seconds. Also, the recording is done in a background service so that the application does not need to be in foreground. To make this, I tried to use Timer but it's not working in background. I've tried so much but it didn't work. Could you help me please?
I found this great tutorial: https://www.raywenderlich.com/5817-background-modes-tutorial-getting-started
I had a similar app to be built some time ago, and I also tried things like you did, but that is very very wrong way to use timer and all to record your location.
First of all, I suggest you to not try to record/ping location explicitly because, it will cause batter drainage. There is something called, significant location change, please go through it in docs. This will trigger you location update in every single significant location change.
But I assume, you really need to ping the location. There is a git repo, link below
Background geo location tracking
Please go though it, it is really nice library out there, I have ever come across, go through its documents. I am sure you will come around and be able to use it for your app. :)
I have just tried to run
meteor run ios
That command emulates my application as an app. But there is just one page that would be interesting to have as an app. Can you control this in some way?
I don't think this is possible. The whole app gets exported regardless of platform, hence the universal/isomorphic apps concept. And in the universal app concept is one that I'm starting to find fault in. That said there is a better middle ground.
We'll call it sudo-universal apps. (probably a horrible name, but whatever :D)
Essentially the concept is that you have 3 codebases, for each device (web/ios/andriod) but share many of the same modules via something like npm, or potentially some other way of sharing code.
Then you can focus on the ui for each device and its strengths and weaknesses, but keep all the important logic you've built.
Check out the following:
https://voice.kadira.io/say-no-to-isomorphic-apps-b7b7c419c634#.3bn5ovts1
https://forums.meteor.com/t/say-no-to-universal-apps/16813/7
Hope this helps!
You can check whether the client code is executed on iOS or not, and change the app accordingly:
if(navigator.userAgent.match(/(iPad|iPhone|iPod)/g)) {
// Disable the links, and redirect to which page you want
}
But Justin's answer is great, a new platform usually needs more than just some tweaks. A quickly developed app has very low value for the user.
I need to scan a website for changes every few minutes and when difference occurs i need inform user with popout window that contains information about that change.
Problem is i can't find solution to that, i tried putting that code in applicationDidEnterBackground but it didnt work. I'm new to swift and mobile programming at all so please be understanding.
Where should i begin? Little tip maybe.
Thank you!
I have submitted my app and been accepted couple of weeks ago. However, I have an issue that one of my critical functionality which is adding pin is not working but it works in building version. Adding pin requires URL connection. Could you please look at the answer that I get from apple developer and guide me please?
It shouldn't be causing your problem (at least not directly), but in general
having networking code like this live inside your UI code is very problematic
for a number of reasons:
-On general architecture grounds, it's a large violation of the MVC (model
view controller) architecture. The pin annotation is obviously heavily tied
to your UI (the view), while networking is clearly part of your backend (the
model).
-Because iOS REQUIRES the main thread to remain responsive, attaching code
that does IO or computation to the main thread is inherently risky. It can be
done and work well, but doing it incorrectly will inevitably lead to crashes.
NSURLConnection works in background and interactions with UI should go on main thread.
So, if you add your pin at the connectionDidFinish method for example, you should do like this:
[mapView performSelectorOnMainThread:#selector(addAnnotation:) withObject:yourAnnotation waitUntilDone:[[NSThread currentThread] isMainThread]];
Hope that helps you. I wrote from windows but the line should work.
I'm not exactly sure about what you are trying to achieve. Are App folks complaining because you are fetching URL directly in the Main thread ? Could you just send a code snippet showing how you fetch urls ?
One option would be to drop the pin (not tied to URL connection at all) and once the pin drops, load your data for the callout or annotation (which is what I'm assuming you are doing). You can always put a loading indicator or progressHUD up to tell the user they need to wait for something. It isn't exactly ideal, but in instances where you need to wait for data, what are you going to do?
Apple really doesn't care about blocking the UI so long as the user is aware you are blocking it. Like a progress bar or progress HUD. The user can see the app is still working and doing something. Not showing anything and having the UI just freeze while it waits for the main thread/main loop to return isn't going to work. It is just bad design and Apple will likely ding you for it.
I would like to create a device that will log when a person falls asleep. Of course, someone can't just open a software application and make an entry say "fall asleep, 10:13pm" and be asleep a few seconds later. Instead, I was thinking about hacking a blackberry to log whenever a person powers it on to check the current time. The specific algorithm is not important, but is it possible to write a piece of code be written to intercept the power on button and write the current time/date to a file? If so, how is it done?
Also, if anyone has a simpler idea, please share.
I haven't tested it, but since you're asking for ideas:
You have your application running in background (or even an app which doesn't extend UIapplication) and have a Task (using Timer and TimerTask) that repeatedly checks if Backlight.isEnabled() returns true. If it does - somebody is using the phone. You can even incorporate an AlertListener class to check when the user has been woken up ;)
The downside of this solution (if it works) is that it is something of a 'busy waiting loop', so intercepting some event would be much better.
As far as writing down the current time is concerned - it's possible and sample code snippets are everywhere, you can of course use the persistent store or an SQLite table to aggregate the results in an interesting way.
Funny thing is I've been thinking about an app like this lately - it might be an good idea.