Updating Apple Watch Complication by fetching data using a URL request - watchkit

I am having a complication that needs to update once in a while by fetching data from a server.
I am trying to fetch the data from the Watch. I am doing so by scheduling a WKRefreshBackgroundTask. When this task fires, I start a URL session to fetch some JSON data from a server.
After the data has been fetched successfully, I complete the WKApplicationRefreshBackgroundTask by calling its setTaskCompletedWithSnapshot(false).
This all seems to work OK-ish, however, I'd rather create a WKURLSessionRefreshBackgroundTask after the WKApplicationRefreshBackgroundTask to download it in the background and consume less time in the background tasks. I think this is not possible, I am not downloading or uploading files. If I understand correctly WKURLSessionRefreshBackgroundTask with a URLSessionConfiguration.background(withIdentifier:) can only be used a for URLSessionUploadTasks or URLSessionDownloadTasks, so I had to forget about that idea. (Please correct me if I misunderstood that).
Now the biggest problem I run into is that when the Watch is locked (taken off the wrist, put on the charging puck, etc.) the URL Requests are not being executed. And thus the data is not been updated. How should we deal with this? The activity compilation simply turns dark when the Watch gets locked and as soon as you unlock the Watch it reloads. Is there anything we can do to understand the Watch is locked/unlocked?
Is it even the right approach to fetch the data from the Watch using a WKApplicationRefreshBackgroundTask, or is it better to wake up the phone and get the phone to request the data using WatchConnectivity? And if so: which WCSessionDelegate functions would you use to achieve that?
If fetching the data directly from the Watch is the way to go: can I set the WKApplicationRefreshBackgroundTask to completed before the request has completed, or should I wait until after the request completed? (i.e., at what point in time should WKApplicationRefreshBackgroundTask.setTaskCompletedWithSnapshot() be called).
I read loads and loads of articles and watched multiple videos. Yet still I find it very hard to find what the correct architecture is to fetch compilation data from a server and get this working rock solid.
Hopefully someone can shine a little light on this matter.

Related

Meteor.logout() and Meteor.call() too slow

I have a web app. I am living a problem about time of Meteor.logout() and Meteor.call(). When i meteor.logout(), it takes time between about 30-40 sec. Same for Meteor.call() as well. About 200-250 clients use this system on the same time.
if a client see about 100-200 items his on app screen this delay time is so much. but 10-20 items, it's a little well. we get data every 5-10 sec as different times each others on these items. I mean, live screen.
I don't get this problem when i work this system on diffrent port with same code and same database by the way just use only me.
I can't figure it. What can be reason it. I need your ideas and help.
The logout function waits for a callback form the server, there is something wrong with the way you have configured your server.
Run the same code on another machine, it should not happen.
You can use this.unblock() in every method and publications.
By default, Meteor process requests one by one, it will queue all the requests coming, if one is processing.
This may be due to the reason that some of the functions doing some bigger functionalities will be requiring more time and all other request to the server have to wait till it ends.
You need to simply place this.unblock() at the starting of every method and publications and it will not block your requests.
Thanks
I solved my problem.
While the collection update process is performed from one side, the meteor publish process is performed from the other side. As the number of clients increases, the server becomes unresponsive. I solved it with Mongodb oplog feature.
Thank you for your interest.
There could be multiple reasons.
There could be unsubscription of collections, which means client and server exchange the list of id's which are being unsubscribed.
You many have reactive UI, which suddenly gets overwhelmed with the amount of data that is being transferred and needs to update itself. (example angular digest cycle always runs after meteor sub/unsub)
Chrome Inspector - Network websocket frame is your best tool understand how soon Meteor logout fires and and if there are any messages being passed back and forth before server retutns the result of logout request.
You may also use this.unblock() feature in subscribe. This way your subscritption run parallelly and don't block each other

Web App in Flaky Internet connection

Have PHP/mySQL/JS-JQuery based web site that records finish times for racers, then sends the time back to the server. The server inserts the finish time in the db, Calculates the finish place based on a handicapping formula. Stores that and send the finish place back to the web page and it is updated on the screen.
It uses Jquery Ajax calls so the page doesn't get reloaded at all.
Everything works fine if the data connection is good.
If the data connection is bad my first version of this page would put a message up that the connection was bad.
Now I am trying to make it a bit smarter, so I have started with the HTML5 feature that tells the browser if it is on or offline(i realize this may not be the best way yet but it works for concept testing)
When a new finish time is recorded(or updated) and we are offline the JS just adds a class of notSent to the tag of the finish time. The finish place and all of the finish places would normally come from the sever are greyed out indicating the data is no longer valid(until it can communicate with the server).
When the browser finds itself back online, A simple jQuery each loop on each notSent class starts re-sending the AJAX requests and if they all get completed it processes the return finish place information and display it as up to date.
It also disables all external links on the page when the browser is offline. This keeps the user from losing the data entry page by accident by clicking a link that will give them a page not found button.
So my last issue, is the browsers reload and close buttons, if the user click these when it is offline they will lose the data entry screen and are out of luck until the connection comes back.
Can I disable these functions as well? A quick Stack-overflow search of this indicates it can be done but most answers give the old, "you really shouldn't and if you think you need to you should rethink your design." warning.
So rethinking my design I start learning about;
HTML 5 local storage (decide I don't need it, since my data is stored already in a input box)
App-cache Manifest for controlling the cache of the page so if reloaded in the browser off line if would get that cached version. After much reading came to the conclusion that this could work on a static page but not mine where the data is updated all the time. Then found that most browsers are deprecating this anyways.
Service Workers seems to be the possible future for contorlling offline caching, but not all browsers support it, it is pretty cumbersome to learn and still very new.
Now I am stuck, Leaning towards preventing browser reloads and defering learning service worker till more support and better examples for a dynamic content pages like mine.
Bottom line- am I missing something here? Is there a easy solution?
I think the best option is to use PouchDB to sync between the client and server and use Background Sync to awake a Service Worker when you regain connectivity. If Service Worker is not present in your browser, it can sync the next time your user open the browser.
You have a similar example of deferred requests explained in the Service Worker Cookbook,

Apple Watch complication network requests

I'm creating a weather application that pulls its information from an online API.
I am able to get the information successfully in the GlanceController and in the InterfaceController. However, I'm a little unsure as to how I should do this for the complication. Can I perform a network request within the ComplicationController class?
If so, How would I go about doing this?
You'll run into issues related to asynchronously fetching data from within the complication data source, mostly due to the data being received after the timeline update is complete.
Apple recommends that you fetch the data from a different part of your app, and have it available in advance of any complication update:
The job of your data source class is to provide ClockKit with any requested data as quickly as possible. The implementations of your data source methods should be minimal. Do not use your data source methods to fetch data from the network, compute values, or do anything that might delay the delivery of that data. If you need to fetch or compute the data for your complication, do it in your iOS app or in other parts of your WatchKit extension, and cache the data in a place where your complication data source can access it. The only thing your data source methods should do is take the cached data and put it into the format that ClockKit requires.
Other ways to approach it:
The best way to update your complication (from your phone once you have received updated weather data) is to use transferCurrentComplicationUserInfo.
Alternately, you could have your watch app or glance cache its most recent weather details to be on hand for the next scheduled update.
If you absolutely must handle it from the complication:
You could have the scheduled timeline update get the extension to start an NSURLSession background task to asynchronously download the information from your weather service. The first (scheduled) update will then end, with no new data. Once the new weather data is received, you could then perform a second (manual) update to reload the complication timeline using the just-received data.
I don't have any personal experience with that approach, mostly because of the unnecessary need for back-to-back timeline updates.

How to update Watch Complication only when the watch is awake, to not use up the daily budget

I have a server that keeps 2 booleans. These booleans change every 15 seconds.
Whenever I wake my Apple Watch, I want the complication to show the current state. How can I do it withough exhausting the budget early on?
The best way would be to fetch the newest state into the complication whenever I wake my watch. The only possible way I see would be to poll the server (either directly or via my phone) every 15 seconds. The problem is that I'd soon use up all the allotted time.
It would be great if I could make the complication only update when the watch was woken up. Can that be done?
Is there a way to not fetch data unless you need it?
No.
By "waking the watch," you're speaking of activating the watch either by interacting with it, or by raising your wrist. Regardless of the manner, the watch can either wake to the watch face, or to the last activity (which is controlled by the Wake Screen setting).
If it wakes to the watch face, this is independent of your app, watch extension, or complication controller. There is no notification you can use to handle that scenario.
If it wakes to an activity, it may not be your activity. If it were your activity, all you could do would be to stop updating when your watch app was active.
Either way, there is no contingency to only update the complication when the watch is awake.
If you think about what you're asking, it runs contrary to Apple's guidelines, as users expect to glance at the watch face and already see current complication data. The system expects you to provide updates when the watch is not awake, so the information will be immediately visible when the watch does wake.
Updating Complication Data
Of the available update approaches, these won't handle your requirements:
PKPushTypeComplication push notifications
This would be ideal, if you were not updating frequently and constantly throughout the day.
Apple applies a daily limit to the number of pushes of this type that you send from your server. If you exceed the limit, subsequent pushes are not delivered.
Scheduled automatic updates
The issue here is that the minimum scheduled update interval is 10 minutes, so you wouldn't have current complication info for the remaining 9-3/4 minutes.
Scheduled updates are useful for apps whose data changes at predictable times. When a scheduled update occurs, ClockKit calls the requestedUpdateDidBegin or requestedUpdateBudgetExhausted method of your data source first.
These approaches might handle your requirements, but you'd have to try them and determine which one meets your needs.
Watch extension + background NSURLSession
This may place more of a drain on battery, but it would work even if not in range of the phone.
Manual update via WCSession transferCurrentComplicationUserInfo
If you're in range of your phone, the more likely approach would be for your phone to (always) poll your server, then provide constant updates.
When your iOS app receives updated data intended for your complication, it can use the Watch Connectivity framework to update your complication right away. The transferCurrentComplicationUserInfo: method of WCSession sends a high priority message to your WatchKit extension, waking it up as needed to deliver the data. Upon receiving the data, extend or reload your timeline as needed to force ClockKit to request the new data from your data source.
Note that complication transfers are budgeted in iOS 10. This approach would not work if you were performing large numbers of updates per day.
Having said all that, an alternate approach would be to monitor these booleans on the server side, and only send out a notification if there was a problem or change. You didn't explain exactly what these booleans indicate, but there are other approaches for monitoring, which would avoid you having to constantly poll a server (from your phone or watch).
If that's not an option, you really should consider either viewing the server data on your phone, or switching to a far less frequent update interval for your complication. Apple discourages such frequent updates, and even their own (stock or weather) complications are not updating several times a minute.
Update:
What if I only wanted to update the complication when user requested it himself(=clicked the complication)? He is not really interested in the state all the time.
Can you (only) update a complication when the watch awakes? No.
Can you update an extension when the extension awakes? Yes.
The user needs to consider what a complication is meant to be. It's designed to be regularly updated to show current information. There's no mechanism to not update the complication because the user is mostly not interested in knowing the state.
Could you tap on a complication to open its app? Yes. But the complication itself would be showing stale data, and the user would have to do more than raise their wrist to see current state.
If you consider what the user is asking, they're not describing a complication (which shows current state), but a way to see the current state when they request it.
That mechanism is different from a complication. They're really describing a Glance (or an app) which the user swipes up (or opens) to see.
If they want live updates, it can be done via WCSession updateApplicationContext.
Use the updateApplicationContext:error: method to communicate recent state information to the counterpart. When the counterpart wakes, it can use this information to update its own state. Sending a new dictionary with this method overwrites the previous dictionary.
The way that works is your phone sends background updates to the watch. The watch stores the most recent update, which will be available to it when your app or Glance wakes up. The user views the app or Glance, and it displays the most recent value which the watch stored. While open, it continues to update itself as new updates arrive. While closed (e.g., inactive, asleep), the watch stores the most recent update on behalf of your app or glance.
If the user doesn't need the app or glance to update itself every 15 seconds, then you wouldn't need to poll, and you could simply use a NSURLSession to fetch the current state when the extension awakes.
If you explain to the user that there's no way to update a complication when the user raises their wrist, and that they don't care about knowing the state all the time (which a complication is meant to do), then show them what a Glance can do, you'll find it far easier to accomplish what the user seems to want, ideally without unnecessarily draining the battery.

long running http process - how to put in separate process?

I know that similar questions have been asked all over the place, but I'm having trouble finding one that relates directly to what I'm after.
I have a website where a user uploads a data file, then that file is transformed and imported into SQL. The file could be up to 50mb in size, and some times this process can take 30 minutes or sometimes even longer.
I realise I need to palm off the actual work to another process, and poll that process on the web page. I'm wondering what the best approach would be though? Being a web developer by trade, I'm finding all this new Windows Service stuff a bit confusing, and I just wanted somewhere to start.
So:
Can I do / should I being doing this with a windows service? if so, how?
Should I use WCF? If this runs under IIS, will I have problems with aspnet_wp.exe recycling and timing out my process?
clarifications
The data is imported into sql, there's no file distribution taking place.
If there is a failure, it absolutely MUST be reported to the user. The web page will poll every, lets say, 5 seconds, from the time the async task begins, to get the 'status' of the import. Once it's finished another response will tell the page to stop polling for status updates.
queries on final decision
ok, so as I thought, it seems that a windows service is the best idea. So as to HOW to get it to work, it seems the 'put the file there and wait for the service to pick it up' idea is the generally accepted way, is there a way I can start a process run by the service, without it having to constantly be checking a database table / folder? As I said earlier, I don't have any experience with Windows Services - I wondered if I put a public method in the service, can I call it somehow?
well ...
var thread = new Thread(() => {
// your action
});
thread.Start();
but you will have problems with that:
what if the import to sql fails? should there be any response to the client
if it fails, how do you ensure the file on a later request
what if the applications shuts down ... this newly created and started thread will be killed either
...
it's not always a good idea to store everything in sql (especially files...). if you want to make the file available to several servers why not distribute them via ftp ...?
i believe that your whole concept is a bit messed up (sry assuming this), and it might be helpful if you elaborate and give us more information about your intentions!
edit:
Can I do / should I being doing this
with a windows service? if so, how?
you can :) i advise you to create a simple console-program and convert this with srvany and sc. you can get a rough overview howto here (note: insert blanks after =... that's a silly pitfall)
the term should is relative, because you did not answer the most important question
what if a record is persisted to the database, telling a consumer that file test.img should be persisted, but your service hasn't captured it or did not transform it yet?
so ... next on
Should I use WCF? If this runs under IIS, will I have problems with aspnet_wp.exe recycling and timing out my process?
you probably could create a WCF-service which recieves some binary-data and then stores this to a database. this request could be async. yes. but what for?
once again:
please give us more insight to your workflow: what are you exactly trying to achieve? which "environmental-conditions" to you have (eg. app A polls db and expects file-records which are referenced in table x to be persisted) ...
edit:
so you want to import a .csv-file. well that changes everything :)
but i won't advise you to use a wcf-service (there could be a usage: eg. a wcf-service which has a method to insert a single row, then your iteration through the file would be implemented in another app... not that good, though).
i would suggest following:
at first do everything in your webapp (as you've already done), but rather use some sort of bulk-insert and do your transformation/logic on the database.
if you have some sort of bottle-neck then, i would suggest you something like a minor job-service, eg:
webapp will upload the file and insert a row to a job-table. the job-service is continiously polling the table/or gets informed via wcf by the webapp (hey, hey, finally some sort of usage for WCF in your scenario... :) ) and then does the import-job, writing a finish-note to a table/or set the state of the job to finished ...
but this is a bit overkill :)
Please see if my below comments helps you to resolve your issue:
•Can I do / should I being doing this with a windows service? if so, how?
Yes you can do this with a windows service. And I think that is the way you should be doing it. You can implement your own service to process your request or you can use the open source code Job Proccessor
Basically the idea is..
You submit a request for processing
the csv file in database table with
some status as not started.
Then your windows service picks up
the request from database table which
are not started and update them as in
progress status.
Once the processing is complete
succesfully /unsuccesfuly your
service updated the database table
with status as Completed / Failed.
And your asp.net page can poll to
database table for the current status
every 5 sec or so.
•Should I use WCF? If this runs under IIS, will I have problems with aspnet_wp.exe recycling and timing out my process?
you should not be using WCF for this purpose.

Resources