iOS8 Today Extension: Detect removed or added today extension - ios

I would like to know how to detect when user removes or adds today extension. If Apple does not have any method to do that, please suggest some ways for me to detect it.
Thank you very much for your time to answer my question.

You cannot detect when the user adds or removes a today extension. You can detect when an extension is run for the first time by reading/writing a value to NSUserDefaults, but that's about it.

If you don't need 100% accuracy, you could post [UIDevice currentDevice].identifierForVendor.UUIDString to an external API every time the widget is loaded. This would give you a time record of every time the user looked at your widget (while connected to the Internet). If you stop receiving regular updates from one UUID:
The user disabled your widget
The user removed your app
The user reset their vendor identifier
As I said, it won't be 100% accurate. That's about as close as you can get.

Related

Why iOS widget doesn't refresh timely even with the containing app in the foreground

I have done some research on the iOS widget refresh mechanism:
1 With containing app in the foreground, the widget refresh is not limited
Read the apple developer docs, I learned that the widget refresh is controlled by the WidgetKit budgets. As it states:
For a widget the user frequently views, a daily budget typically includes from 40 to 70 refreshes
But in the following cases, the reload doesn’t count against the widget’s budget:
The widget’s containing app is in the foreground.
The widget’s containing app has an active audio or navigation session.
The system locale changes.
Dynamic Type or Accessibility settings change.
2 We can use WidgetCenter.shared.reloadTimelines to refresh widget from containing app
The same doc says:
In the game widget example above, if the app receives a push notification indicating a teammate has given the character a healing potion, the app can tell WidgetKit to reload the timeline and update the widget’s content.
3 I have seen some great implementation on this
Apps like LiveIn gives me a smooth user experience with widget refresh timely when I got a post from my friends (as long as the containing app is in the foreground, guess they can improve this with Background Refresh).
This product is not limited by the daily 40 to 70 refreshes budget limitation, and I get a little delay (little enough to be ignored) between the picture display in containing app and the widget.
4 But I'm still stuck here
But when I tried to build an app using the above API WidgetCenter.shared.reloadTimelines or WidgetCenter.shared.reloadAllTimelines to notify the widget to refresh with data stored in UserDefaults, my widget does not respond to the API call timely. Sometimes, it may be stuck for more than 10 minutes, which is a terrible case far far away from the product I mentioned above.
5 Some hack attempts
I have looked through so many Stackoverflow QAs & blogs and do find some tricky things in the iOS widget. For example, the View._clockHandRotationEffect(.secondHand, in: .current, anchor: .center) API can be used to refresh the widget view without limits (usually used to build clock based applications).
But it seems to have nothing to do with the message notification between the containing app and the widget (or it is just I have not figured it out yet).
6 My question
So here comes my question. As some apps existing on the iOS store already have the capability to notify widgets timely, why can I still not get the smooth user experience guided by the official documentation? Do I miss some things important here, or they are just using other private APIs that are out of my sight?
The code is not complex and the Xcode signing is annoying, so I do not prepare a minimal project to reproduce this. You may take pawello2222/WidgetExamples as a demo if you want to give it a try. Any hints or clues will be highly appreciated!
Finally, we get a smooth user experience. The solution is quite strange at first glance but works like a charm compared to our earlier implementation.
All you need to do is to call WidgetCenter.shared.reloadTimelines or WidgetCenter.shared.reloadAllTimelines after the application goes into foreground as soon as possible.
Why? As the doc Managing Your App's Life Cycle states:
a foreground app has the user’s attention, so it has priority over system resources, including the CPU
The doc is clear but the time is also important, there are some phenomenons we test to be as is but cannot be found in any official documentation (running app in release, not debug mode with xcode connected):
Launch the app in the foreground all the time, notifying the widget to refresh the view by calling WidgetCenter.shared.reloadTimelines or WidgetCenter.shared.reloadAllTimelines constantly, the delay will increase significantly as time goes by
When calling WidgetCenter.shared.reloadTimelines or WidgetCenter.shared.reloadAllTimelines after the app starts ASAP, the widget view will refresh instantly (almost 100% success rate)
I've seen many developers stuck in the refresh mystery of the iOS widget and give up using it finally. Hope my experience will help others a better understanding and make a decision more quickly.
#Lebecca I just want to add more insights from my side. Hope you find it helpful.
In my app I call WidgetCenter.shared.reloadAllTimelines just before my app goes to background. I have no problem with this Reload at all. Reload success rate is 100%.
From my experience, when app goes to background, you have few seconds to do some work, after that the process is killed. It is possible that your widget need more time to reload than the time allowed. That's why you do not see the Reload consistently. And that the solution that you call WidgetCenter.shared.reloadTimelines as soon as application goes into foreground fix this because you give the widget "more" time for it to finish the Reload. (When app in foreground, you do not have limit on processing time.)
There are 3 parts involving widget reload.
Data for the widget: if your app need to run some code or retrieve some information from the network. Be sure it doesn't take too long, otherwise the widget reload process can be killed.
Complexity of the widget: Here I mean whether your widget view is complex or not. Many Stacks, many elements will potentially cause the widget Reload to fail.
How many timeline entries you have: Say if you have 100 timeline entries for a day, this might cause some problems as well. You need to find the balance of timeline entries and number of Reloads you plan to run on a day.
Widget Reload budget. I always try to keep it around 40-50 times per day, just to be safe.
Widget is really a mystery. Above are all from my experience.

Swift: SKStoreReviewController - how often can it be called?

The documentation says that an app can ask a User three times per year via SKSToreReviewController to place a rating.
Most suggest to save a variable in UserDefaults and call the function after a couple of uses. What happens if you call the function more than three times per year? Will the App Store just ignore the calls and after a year asks for a rating again or will you get some kind of error?
And what happens if the app has been updated (ie. a jump from version 1.0 to version 2.0)? Will the 3 requests be reset?
In short, you choose the appropriate time to display the alert, but the system will decide whether to actually show the alert or not. So don't worry about "over-calling" as long as you don't call it as a response to user interaction.
Although you should call this method when it makes sense in the user experience flow of your app, the actual display of a rating/review request view is governed by App Store policy. Because this method may or may not present an alert, it's not appropriate to call it in response to a button tap or other user action.
Highlight mine.
https://developer.apple.com/documentation/storekit/skstorereviewcontroller/2851536-requestreview
As for your second question, the only reference I can find regarding how many times it might be displayed is "3 times per year". It doesn't mention 3 times per app version or update. Use this API wisely.

SKStoreReviewController requestReview() may or may not present and alert?

I'm taking a look at the new requestReview() API that uses SKStoreReviewController. The documents state:
"Although you should call this method when it makes sense in the user experience flow of your app, the actual display of a rating/review request view is governed by App Store policy. Because this method may or may not present an alert, it's not appropriate to call it in response to a button tap or other user action."
Does anyone have any experience using this API. What exactly are the factors that determine if the rating view is shown or not? I'm guessing it's not shown if called too frequently.. Anybody have any insight on this? Thanks!
You're right that it won't show if called too frequently.
SKStoreReviewController will only allow prompting a user to review your application 3 times at most, even if you ship more versions than that during the year.
There might be more restrictions beneath the surface as well.
Source: http://daringfireball.net/2017/01/new_app_store_review_features
According to iOS Human Interace Guildelines
The system automatically limits the display of the prompt to three occurrences per app within a 365-day period.

Find correct time on iOS device

I want to find out correct time on iOS devices even though user have set wrong time manually.
In the setting->General->Date & Time there is option of Set Automatically if that option is uncheck by the user then how can i find the correct time programmatically.
Use NTP protocol for getting a current time or serve a time from your server and get it on application launch.
Apple doesn't provide by default any way to get time from NTP unfortunately and all time related function are using local time that user can change.
I have a 'web service' on my site which serves you the current time in milliseconds since the Unix epoch, one request, one response, nothing else.
I think this is the wrong place for this question. Try Apple's forums.
Because there is no way to get current time form ios device when user update time manually.
Sweet & smart .........

How to send in-app announcements to people using my iOS app?

I have a couple apps on the Apple App Store and would like some way to send announcements to users whenever I want. Basically, I want to remotely change the text of an IUAlertview and only trigger it to appear if I want it to (upon app opening and only if I updated the message).
So far I have no problem making the IUAlertview appear on when the app opens, and I can easily program an NSUserDefault flag to only make the IUAlertview appear under certain circumstances, but really have no idea how to dynamically change the UIAlertview text without resubmitting my app to Apple continuously.
Can someone please explain how this is done? Thanks!
One way to do this is to have your app periodically (or upon each launch) check a file on a website that you control and if there is changed text (or a version number, or newer date than the last time an alert was displayed) there, then display that changed text in your UIAlertView.

Resources