i developed an app which ranges for beacons in the background using ibeacon API. As it uses the core location and bluetooth , so i enabled the Location, Bluetoothconfiguration from the capabilities. So after running my app , ranging happening in background, but after 5-10 min between my app terminates, when i launch the app it is again showing the splash and the login page, so after google i learned that app runs in background with some extra time.
To overcome the app termination i'm using the below code in a method and calling that method in applicationDidEnterBackground.
-(void)startBackgroundTask
{
if(bgTask != UIBackgroundTaskInvalid)
{
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self endBackgroundUpdateTask];
NSLog(#"your time is over");
//you can call start once again to get more time
}];
}
-(void) endBackgroundUpdateTask
{
[[UIApplication sharedApplication] endBackgroundTask: bgTask];
bgTask= UIBackgroundTaskInvalid;
[[NSNotificationCenter defaultCenter]
postNotificationName:#"TimerOutStartMonitering" object:nil];
}
After using the above code and debugging , my app ranging stops once the UIBackgroundTaskInvalid. How can i achieve the both tasks 1)My App shouldn't terminate once the background time is finished.
2)My ranging for beacons shouldn't stop.
Is it possible?
Please help me out.
Unfortunately, this is not possible. You cannot run a background task like this indefinitely. This mechanism is only intended for short term app cleanup before termination. See here.
Apps running background tasks have a finite amount of time in which to run them. (You can find out how much time is available using the backgroundTimeRemaining property.)
Because of this, iBeacon ranging is limited to a few seconds in the background. You can use IBeacon monitoring to relaunch your app and range again on beacon discovery, but again, you will only get a small of ranging time unless the user brings the app tyo the foreground.
Related
I have a weird problem in our current Xamarin project. As the app sends a larger chunk of data to the server, to protect it when app gets backgrounded, we're starting a long-running task (using the UIApplication.SharedApplication.BeginBackgroundTask / UIApplication.SharedApplication.EndBackgroundTask API). What's weird is that this works great when I build and run from my machine but several of my colleagues get a timeout error when running the exact same scenario when the app was build/deployed from their machines.
As far as I understand it running stuff in a long-running task like this should work. I should not have to specify backgrounding capabilities in info.plist. Also, as the HttpClient employ NSUrlSession for sending/receiving it should be protected from interruptions when the app gets backgrounded, right?
I can't figure out why the same code yields different behavior on the same device when built with different Macs. Could there be some setting somewhere in VS that could be local to the machine that would affect this behavior?
I'm out of ideas now so any hints would be greatly appreciated.
This is an example of code that works/fails depending on the Mac that built/deployed it:
public async Task Submit()
{
// ... some irrelevant code
BackgroundTask.Run(async () => await submitAsync()); // Form-level encapsulation of the UIApplication.SharedApplication.BeginBackgroundTask API
// ... more irrelevant code
}
private async Task submitAsync()
{
if (!IsSubmitAllowed)
return;
IsBusy = true;
IsGoBackAllowed = IsGoNextAllowed = false;
var statusIndicator = new StatusIndicator();
await PopupNavigation.Instance.PushAsync(statusIndicator);
try
{
statusIndicator.Status = "Saving TI";
statusIndicator.Progress = 0.1;
var submitted = await _service.SubmitAsync(Model); // ERROR! causes timeout exception for some
var submittedId = submitted.BackendId;
// ... etc.
Both of your assumptions seem to be wrong.
First, beginBackgroundTaskWithExpirationHandler: doesn't grant unlimited background activity. Most notably:
https://developer.apple.com/documentation/uikit/uiapplication/1623031-beginbackgroundtaskwithexpiratio?language=objc
Apps running background tasks have a finite amount of time in which to
run them
Second, NSURLSession isn't enabled by default in the HttpClient, and overal NSURLSession is not something that handles transfers in the background by default, that is just possibility and it would be natural that HttpClient doesn't use this mode. Again check the documentation: https://developer.apple.com/documentation/foundation/nsurlsession
I am trying to replicate the result of WWDC talk on syncing core data with cloud kit automatically.
I tried three approaches:
Making a new master slave view app and following the steps at in
wwdc 2019 talk, in this case no syncing happens
Downloading the sample wwdc 2019 app also in this case no symcing happens
I made a small app with a small core data and a cloud kit container in this case syncing happens but I have to restart the app. I suspected it had to do with history management so observed the NSPersistentStoreRemoteChange notification not nothing receives.
Appreciate any help.
I also played around with CoreData and iCloud and it work perfectly. I would like to list some important points that may help you go further:
You have to run the app on a real device with iCloud Acc We can now test iCloud Sync on Simulator, but it will not get notification automatically. We have to trigger manually by select Debug > Trigger iCloud Sync
Make sure you added Push Notification and iCloud capability to your app. Make sure that you don't Dave issue with iCloud container (in this case, you will see red text on iCloud session in Xcode)
In order to refresh the view automatically, you need to add this line into your Core Data Stack: container.viewContext.automaticallyMergesChangesFromParent = true.
Code:
public lazy var persistentContainer: NSPersistentCloudKitContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentCloudKitContainer(name: self.modelName)
container.viewContext.automaticallyMergesChangesFromParent = true
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
When you add some data, normally you should see console log begin with CloudKit: CoreData+CloudKit: ..........
Sometimes the data is not synced immediately, in this case, I force close the app and build a new one, then the data get syncing.
There was one time, the data get synced after few hours :(
I found that the NSPersistentStoreRemoteChange notification is posted by the NSPersistentStoreCoordinator and not by the NSPersistentCloudKitContainer, so the following code solves the problem:
// Observe Core Data remote change notifications.
NotificationCenter.default.addObserver(
self, selector: #selector(self.storeRemoteChange(_:)),
name: .NSPersistentStoreRemoteChange, object: container.persistentStoreCoordinator)
Also ran into the issue with .NSPersistentStoreRemoteChange notification not being sent.
Code from Apples example:
// Observe Core Data remote change notifications.
NotificationCenter.default.addObserver(
self, selector: #selector(type(of: self).storeRemoteChange(_:)),
name: .NSPersistentStoreRemoteChange, object: container)
Solution for me was to not set the container as object for the notification, but nil instead. Is it not used anyway and prevents the notification from being received:
// Observe Core Data remote change notifications.
NotificationCenter.default.addObserver(
self, selector: #selector(type(of: self).storeRemoteChange(_:)),
name: .NSPersistentStoreRemoteChange, object: nil)
Update:
As per this answer: https://stackoverflow.com/a/60142380/3187762
The correct way would be to set container.persistentStoreCoordinator as object:
// Observe Core Data remote change notifications.
NotificationCenter.default.addObserver(
self, selector: #selector(type(of: self).storeRemoteChange(_:)),
name: .NSPersistentStoreRemoteChange, object: container.persistentStoreCoordinator)
I had the same problem, reason was that iCloudDrive must be enabled in your devices. Check it in the Settings of every your device
I understand this answer comes late and is not actually specific to the WWDC 19 SynchronizingALocalStoreToTheCloud Apple's sample project to which OP refers to, but I had syncing issues (not upon launch, when it synced fine, but only during the app being active but idle, which seems to be case 3 of the original question) in a project that uses Core Data + CloudKit with NSPersistentCloudKitContainer and I believe the same problems I had - and now apparently I have solved - might affect other Users reading this question in the future.
My app was built using Xcode's 11 Master-Detail template with Core Data + CloudKit from the start, so I had to do very little to have syncing work initially:
Enable Remote Notifications Background Mode in Signing & Capabilities for my target;
Add the iCloud capability for CloudKit;
Select the container iCloud.com.domain.AppName
Add viewContext.automaticallyMergesChangesFromParent = true
Basically, I followed Getting Started With NSPersistentCloudKitContainer by Andrew Bancroft and this was enough to have the MVP sync between devices (Catalina, iOS 13, iPadOS 13) not only upon launch, but also when the app was running and active (thanks to step 4 above) and another device edited/added/deleted an object.Being the Xcode template, it did not have the additional customisations / advanced behaviours of WWDC 2019's sample project, but it actually accomplished the goal pretty well and I was satisfied, so I moved on to other parts of this app's development and stopped thinking about sync.
A few days ago, I noticed that the iOS/iPadOS app was now only syncing upon launch, and not while the app was active and idle on screen; on macOS the behaviour was slightly different, because a simple command-tab triggered sync when reactivating the app, but again, if the Mac app was frontmost, no syncing for changes coming from other devices.
I initially blamed a couple of modifications I did in the meantime:
In order to have the sqlite accessible in a Share Extension, I moved the container in an app group by subclassing NSPersistentCloudKitContainer;
I changed the capitalisation in the name of the app and, since I could not delete the CloudKit database, I created a new container named iCloud.com.domain.AppnameApp (CloudKit is case insensitive, apparently, and yes, I should really start to care less about such things).
While I was pretty sure that I saw syncing work as well as before after each one of these changes, having sync (apparently) suddenly break convinced me, for at least a few hours, that either one of those modification from the default path caused the notifications to stop being received while the app was active, and that then the merge would only happen upon launch as I was seeing because the running app was not made aware of changes.
I should mention, because this could help others in my situation, that I was sure notifications were triggered upon Core Data context saves because CloudKit Dashboard was showing the notifications being sent:
So, I tried a few times clearing Derived Data (one never knows), deleting the apps on all devices and resetting the Development Environment in CloudKit's Dashboard (something I already did periodically during development), but I still had the issue of the notifications not being received.
Finally, I realised that resetting the CloudKit environment and deleting the apps was indeed useful (and I actually rebooted everything just to be safe ;) but I also needed to delete the app data from iCloud (from iCloud's Settings screen on the last iOS device where the app was still installed, after deleting from the others) if I really wanted a clean slate; otherwise, my somewhat messed up database would sync back to the newly installed app.
And indeed, a truly clean slate with a fresh Development Environment, newly installed apps and rebooted devices resumed the notifications being detected from the devices also when the apps are frontmost.So, if you feel your setup is correct and have already read enough times that viewContext.automaticallyMergesChangesFromParent = true is the only thing you need, but still can't see changes come from other devices, don't exclude that something could have been messed up beyond your control (don't get me wrong: I'm 100% sure that it must have been something that I did!) and try to have a fresh start... it might seem obscure, but what isn't with the syncing method we are choosing for our app?
We created a Qt HTTP server derived from QTcpServer.
Each incoming client connection is handled in a new thread like this:
void WebClientThread::run()
{
// Configure the web client socket
m_socket = new QTcpSocket();
connect(m_socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
connect(m_socket, SIGNAL (error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
// Create the actual web client = worker
WebClient client(m_socket, m_configuration, m_pEventConnection, m_pThumbnailStreams, m_server, m_macAddress, 0 );
// Thread event loop
exec();
m_pLog->LOG(L_INFO, "Webclient thread finished");
}
//
// Client disconnect
//
void WebClientThread::disconnected()
{
m_socket->deleteLater();
exit(0);
}
This code works, but we experienced application crashes when it was executed while the NTP connection of our device kicked in and the system time was corrected from the epoch 01/01/1970 to the current time.
The crash could also be reproduced when running the application and meanwhile changing the system time from a script.
The application runs fine - even when the system time changes on the fly like this:
void WebClientThread::run()
{
// Configure the web client socket
m_socket = new QTcpSocket();
connect(m_socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
connect(m_socket, SIGNAL (error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
// Create the actual web client = worker
WebClient client(m_socket, m_configuration, m_pEventConnection, m_pThumbnailStreams, m_server, m_macAddress, 0 );
// Make this thread a loop,
exec();
delete m_socket;
m_pLog->LOG(L_INFO, "Webclient thread finished");
}
//=======================================================================
//
// Client disconnect
//
void WebClientThread::disconnected()
{
exit(0);
}
Why would deleteLater() crash the application when the system time is shifted ?
Additional information:
OS = embedded linux 3.0.0. Qt = 4.8
The socket is a connection between our Qt web server application and the front end server = lighttpd. Could it be that lighttpd closes the socket when the system time shifts 47 years and the request is still being processed by our web server?
I could reproduce it by sending requests to the server while in parallel running a script that sets date to 1980, 1990 and 2000. It changes once a second.
This smells of wrong use of Qt threads. I suggest you do not subclass QThread, if you call exec() from its run() method, because it's just too easy to do things wrong way if you do that.
See for example https://wiki.qt.io/QThreads_general_usage to see how to set up a worker QObject for a QThread, but the gist of it is, create subclass of QObject and put your code there. Then move an instance of that to a QThread instance, and connect signals and slots to make things happen.
Another things, you normally shouldn't use threads for Qt Networking, like QTcpSocket. Qt is event based and asynchronous, and as long as you just use signals and slots and never block in your slot methods, there is no need for threads, they only complicate things for no benefit. Only if you have time-consuming calculations, or if your program truly needs to utilize multiple CPU cores to achieve good enough performance, only then look into multithreading.
Hello i am new to developing application. now i am working on an app that have to track the location so it must work in the background when i do so it works will but when i get back to the app the UI is not updated
if (!App.RunningInBackground)
{
Dispatcher.BeginInvoke(() =>
{
one.Text = args.Position.Coordinate.Latitude.ToString();
two.Text = args.Position.Coordinate.Longitude.ToString();
});
}
and on the output
The thread 0x7b4 has exited with code 259 (0x103).
i do not know what is UI thread and i checked Google.
If you want to have an app that runs in background, you should use background agents.
For a good quick start this link is best.
Best practices and advices are found here.
And you want to run your app in background and want to update the textbox in foreground? what do you mean?
UI thread means the main thread in phone foreground app where all the activities take place. Any new async task has to be spawned from this UI thread only.
You have a code because your app has successfully exited the foreground.
We have integrated flash game (crazytaxi.swf) inside Windows form application in VS Express 2012 for Windows Desktop.We are controlling game with the help of gestures using leapmotion controller.
What happens is when we run project in VS2012,game starts normally.We play game using gesture (left,right etc.).But after some time controller stops listening by exiting its thread.We can see that in output window.
"The thread '' (0x1b50) has exited with code 0 (0x0)." this we get in output window.
We are not getting how to overcome this challenge.
You didn't provide enough information but from what I gather, your LEAP thread ran to completion and closed. This can occur if you declare and initialize your listener and controller variables in a function and the variables go out of scope when the function is executed. This causes Garbage Collector to dispose both controller and listener at what might seemingly appear as random (non reproductable) moments. To fix this issue, create a singleton for the controller and listener - this can boil down to simply defining a static controller and listener variables in some class. This way the listener and controller objects will never go out of scope and get disposed by the GC.
"The thread '' (0x1b50) has exited with code 0 (0x0) basically says that:
The thread with the ID 6992 ran and completed the operation successfully.
System Error Codes (0-499)
The question is, does the device stop tracking?
Here are my 0x0's from my Leap Motion app (its working fine):
The thread 'vshost.NotifyLoad' (0x364) has exited with code 0 (0x0).
The thread '' (0x3348) has exited with code 0 (0x0).
The thread 'vshost.LoadReference' (0x37c8) has exited with code 0 (0x0).
Also, on a side note, because it has nothing to do with the error code - are you removing the listener from the controller, and then disposing of them both when the application is being closed? Not properly disposing of objects will cause problems.
A second note - onExit and onDisconnet are two different things.
onDisconnect(controller:Controller):void
Called when the Controller object disconnects from the Leap Motion software.
Listener
onExit(controller:Controller):void
Called when this Listener object is removed from the Controller or the Controller instance is destroyed.
In case somebody is having similar problems here is the reply I sent over email after having a look at the code:
I've looked at the code, since you only sent me a few files I had to comment out the the references to classes that was not included in the zip.
The code runs fine with 3 different Leap Motion devices - when I comment out from the method, what I suggest is:
Update the SDK. I used .Net 4 dll and the latest version of the SDK which today is: v.1.0.8.7665
Dispose the objects once you are done using them. Dispose Frames after using them, Remove listener from the Controller, and dispose Controller when the device isn't used anymore or the application is being closed.
I noticed some Timers and DispatcherTimers they were being created, but I couldn't find any references to where they were being used. What are these being used for? DispatcherTimer doesn't belong in a windows forms application.
My best guess - and I hate to guess - is that there is a threading problem OR that the objects aren't being disposed correctly - OR you are using an SDK version that had bugs.
I have two applications on GitHub - feel free to use the code as you want. There is one for WPF and one for Windows Forms - both need to be updated for latest SDK as some things have been deprecated (such as the Screen class) in later versions of the SDK.
WPF:
https://github.com/IrisClasson/Leap-Motion
Windows Forms:
https://github.com/IrisClasson/LeapMotion_WinForms_Demo_OLD_SDK
Disclaimer: I don't do much, if any WinForms development
I had a same issue with my WPF application and Leap Motion code but the code works fine with a console application.
In WPF when I globally declared the Leap-Listener and the controller Object, I did not face the error any more and the Listener is active all time.
Just declare the listener and controller in the class (globally) from which you call the listener
public static LeapListener listener;
public static Controller controller;
Now use this listener object, and add it to the controller and enable gesture property of the controller in a function or a constructor.
listener = new LeapListener();
controller.AddListener(listener);
controller = new Controller();
This should solve the issue. If the problem still persists (detection problem), simply initialize and add the same listener object to the controller object onExit event. Now the gesture and other properties exist as you are not creating a new instance of the controller again.