How to clear installed widgets on iOS app - ios

In last version of iOS app we have implemented widget feature, but in the coming release we have decided to remove the widget extension.
If the user has already added widget to his Home Screen and when ever user updates his/her application with latest code that does not contain widget extension, still user is able to view blank widget.
Is there any way to clear/remove widgets programatically from main app.

If you set the supportedFamilies modifier on the WidgetConfiguration to [] then the widget no longer shows in the widget gallery. That might be an option.
public var body: some WidgetConfiguration {
StaticConfiguration(
kind: kind,
provider: Provider()
) { entry in
widget_mainEntryView(entry: entry)
}
.configurationDisplayName("Foo")
.description("Foo")
.supportedFamilies([])
}

Related

Implementing Messages - shared with you feature on iOS15

iOS15 has a new shared with you feature on apple's apps- safari, apple news, music, movies, etc. For example, if any of my friends share the news link from apple news to me on apple messages, when I open the Apple news and scroll to the home page I get a section for 'shared with you' articles. It also shows the name of the friend how shared it with me.
I am wondering is there any API/source I can use to provide the same experience on my app? I found https://developer.apple.com/videos/play/wwdc2021/10187/, but this video doesn't explain the 'shared with you' implementation. Please share ideas for the implementation. Thanks in advance.
With iOS 16 it will be possible to implement Shared with You support for your app.
Check out this WWDC22 Session Add Shared with You to your app.
Well I spent a bunch of time on implementing Shared With You for iOS 16. There is not much information available beyond the WWDC video listed in the previous answer. But, I did get it working. Here was my approach.
Make sure your device is running at least iOS 16.0.3. It didn't start working until I installed this version and did the rest of the following.
Follow these instructions: https://www.avanderlee.com/swift/shared-with-you/
When implementing Universal Links, you just have to return true (in your app delegate) once you recognize the universal link as one of the links from Messages that contain Shared With You content. You do NOT need to implement SWCollaborationMetaData. It is kinda implied in the Apple docs that you might need to do this but you do not.
In the SharedWithYouMonitor (as referenced in item 2 above), set up a array that can hold all of your hightlights. You will need this array in the view that displays the Shared With You content. Append each hightlight to the array in the delegate method highlightCenterHighlightsDidChange...
#Published var sharedItems = [SharedWithYouModel]()
I set up a simple model for the hightlights. Something like:
import Foundation
import SharedWithYou
#available(iOS 16.0, *)
struct SharedWithYouModel: Identifiable {
var id = UUID()
let swHighlight: SWHighlight
let url: URL
}
In your view where you will show the SharedWithYou content, mark it as:
#available(iOS 16.0, *)
struct SharedWithYou: View {
#Environment(\.horizontalSizeClass) var sizeClass
#StateObject var monitor = SharedWithYouMonitor()
var gridItemLayout = [GridItem(.adaptive(minimum: 100, maximum: 150), spacing: 30)]
var body: some View {
ZStack {
ScrollView {
Text("ContentOne")
.foregroundColor(Color(hex: 0x0DB9D6))
LazyVGrid(columns: gridItemLayout, spacing: horizontalSpace) {
ForEach(monitor.sharedItems) { item in
SharedWithYouView(.........
Other: I used the SWAttributionView suggested in 2. Make sure your users have Shared With You on for your app in Settings--Messages--Shared With You. You can send content to yourself in Messages to test. It seems that content received in Messages will only show if the recipient pins the content in Messages and/or the recipient has the sender as a contact in their Contacts. I guess this is for privacy control.

Setting language across whole app - SwiftUI

I am looking to add multiple languages to my app and so I have created the different String files and have added them to my localisations. I have a settings page in my app where I want them to be able to select the language the app is in, and the whole app is changed.
VStack{
Button("English"){
//set app to English
}
Button("Francais"){
//set app to French
}
Button("Cymru"){
//set app to Welsh
}
.....
}
I've found the modifier .environment(\.locale, init(identifier: "en")) but I believe this modifier needs to be added to every view and I was wondering if there is an easier way to do this? I want the language to be saved to user defaults too.

ios 14 widget: How to reload timeline after UserDefaults changed

I have a ios 14 widget that refresh every 5 minutes
let timeline = Timeline(entries: entries, policy: .atEnd)
The entries depends on the configuration on my MainApp.
I use UserDefaults to share data between MainApp and Widget.
#AppStorage("FollowingCatalog", store: UserDefaults(suiteName: "group.vn.f19.com"))
var catalogItemsData: Data = Data()
I've successfully mirrored the widget content base on UserDefaults data. BUT my problem is the my widget refresh the UI only after .atEnd policy, every 5 minutes
That cause a bad UX
How can I refresh widget content immediately right after my configuration in UserDefaults was changed?
Thanks for your supports.
To clarify the whole workflow, I add some note here:
You can call WidgetCenter not only from widget but from your main app.
WidgetCenter.shared.reloadAllTimelines()
WidgetCenter.shared.reloadTimelines(ofKind: "com.myApp.myWidget........")
So the flow is:
User change something on MainApp, eg: I rearrange the stock items in the following list
MainApp save the data to UserDefaults, eg: save the list item order
MainApp trigger reload widget by:
WidgetCenter.shared.reloadTimelines(ofKind: "mone24h_widget")
You can get the kind by looking into your widget entry file:
#main
struct mone24h_widget: Widget {
let kind: String = "mone24h_widget"
Widget will reload the timeline, I will get the shared data from UserDefaults here. Done the work. Eg: Re-render my stocks list base on the arrangement passed from MainApp
In Keeping a Widget Up to Date by Apple, to inform your widgets to update its timeline and its content, you call:
WidgetCenter.shared.reloadAllTimelines()
This reloads all widgets that your app has. If you want to reload a specific widget (in the case your app has multiple different widget types), use WidgetCenter.shared.reloadTimelines(ofKind: "com.myApp.myWidget") instead.
BTW, if you're using react-native, I've already created a module to support this issue:
react-native-widget-bridge

Sharing UserDefaults between main app and Widget in iOS 14

I am writing a widget for iOS, seems UserDefaults is not accessible in the widget, I added app group as following, still it's nil:
let prefs = UserDefaults(suiteName:"group.myco.myapp")
Still when I try to read something from prefs which I set in the main app, it's nil here.
You'll need to add the AppGroup capability to the widget target. Select the project, then select the widget target, go to the Signing & Capabilities tab, and click the + Capability button. Then choose AppGroup and configure it with your group.
As #Ilya Muradymov commented blow
You need to set data for corresponding group UserDefault first if you want to get the data between widget and container app:
//object-C
[[NSUserDefaults.alloc initWithSuiteName:#"group.com.your.groupname"] setObject:mObject forKey:#"xxxxxxxx"];
//swift
UserDefaults(suiteName:"group.com.your.groupname").set(mObject, forKey: "xxxxxxxx")

Determine if the widget is enabled

Is there any way to determine if my Today Widget is already added to Notification Centre by user? I need to know so I can change some Labels in host app accordingly.
There is no API for that, but you could have your today widget write something to the shared container that you can read from your app to determine if it's been displayed. The main problems with that are that it won't happen until the widget has been displayed at least once, and you can't relly tell if they've installed and then removed it.
func widgetHasRun() {
if let sharedContainer = NSUserDefaults(suiteName: "group.com.my.app") {
sharedContainer.setBool(true, forKey: "today widget installed")
sharedContainer.synchronize()
}
}
We use this technique to determine whether we should prompt new users to install our widget.

Resources