{"id":1025,"date":"2024-08-19T04:03:49","date_gmt":"2024-08-19T04:03:49","guid":{"rendered":"https:\/\/blog.200oksolutions.com\/?p=1025"},"modified":"2025-12-04T07:44:08","modified_gmt":"2025-12-04T07:44:08","slug":"building-dynamic-ios-widget-with-api-integration","status":"publish","type":"post","link":"https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/","title":{"rendered":"Build a Dynamic iOS Widget with API Integration"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\"><strong>Introduction<\/strong><\/h2>\n\n\n\n<p>In our <a href=\"https:\/\/blog.200oksolutions.com\/creating-ios-widgets-with-widgetkit-and-swiftui\/\">previous blog<\/a>, we covered widget extensions and their benefits for providing quick, at-a-glance information on the home screen. This blog will walk you through a practical example of integrating iOS widget APIs with real-time data, showing you how it all works step-by-step.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe title=\"Build a Dynamic iOS Widget with API Integration\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/7gEq8sZPEEo?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Overview of Real-Time Data Integration<\/strong><\/h2>\n\n\n\n<p>In this blog, we&#8217;ll demonstrate how to integrate real-time data into iOS widgets using API calls. This practical example will guide you through connecting a widget with an API to fetch and display live data.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Prerequisites<\/strong><\/h2>\n\n\n\n<p>Before we dive into the code, make sure you have the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Xcode installed (latest version recommended)<\/li>\n\n\n\n<li>Basic knowledge of Swift and SwiftUI<\/li>\n\n\n\n<li>An existing iOS project to add the widget extension to<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>A.Setting Up the Widget Extension<\/strong><\/h3>\n\n\n\n<p>Start by adding a widget extension to your existing iOS project.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Open your Xcode project.<\/li>\n\n\n\n<li>Go to <strong>File &gt; New &gt; Target.<\/strong><\/li>\n\n\n\n<li>Choose Widget Extension from the list and click Next.<\/li>\n\n\n\n<li>Name your widget (e.g., &#8220;TrialWidget&#8221;) and ensure that &#8220;Include Configuration Intent&#8221; is unchecked for this example.<\/li>\n\n\n\n<li>Click Finish.<\/li>\n<\/ol>\n\n\n\n<p>Your project will now include a new target with some boilerplate code for the widget.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Designing the Widget UI with SwiftUI<\/strong><\/li>\n<\/ul>\n\n\n\n<p>We&#8217;ll design the user interface (UI) of the widget using SwiftUI. Our widget will display a list of posts fetched from an API.<br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>struct TrialWidgetEntryView: View {\n\n&nbsp;&nbsp;&nbsp; var entry: Provider.Entry\n\n&nbsp;&nbsp;&nbsp; var body: some View {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VStack(alignment: .leading, spacing: 10) {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ForEach(entry.posts, id: \\.id) { post in\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VStack(alignment: .leading) {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Text(post.title)\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .font(.headline)\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Text(post.body)\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .font(.subheadline)\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .lineLimit(3) \/\/ Adjust based on the size\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Divider().padding(16)\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Replace Divider with Static Image\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Image(\"200ok\")\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .resizable()\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .scaledToFit()\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .frame(height: 100)\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .cornerRadius(8)\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .padding()\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .widgetURL(URL(string: \"myapp:\/\/PostSummary\/\\(post.title.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? \"\")\"))\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .padding()\n\n}\n\n&nbsp; private func fetchData(completion: @escaping (&#91;Post]) -&gt; Void) {\n\n&nbsp;&nbsp;&nbsp; let url = URL(string: \"https:\/\/jsonplaceholder.typicode.com\/posts\")!\n\n&nbsp;&nbsp;&nbsp; let task = URLSession.shared.dataTask(with: url) { data, response, error in\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; guard let data = data, error == nil else {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print(\"Failed to fetch data\")\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let posts = try? JSONDecoder().decode(&#91;Post].self, from: data)\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; completion(posts ?? &#91;])\n\n&nbsp;&nbsp;&nbsp;&nbsp; }\n\n&nbsp;&nbsp;&nbsp;&nbsp; task.resume()\n\n&nbsp;}\n\n&nbsp; struct Post: Decodable {\n\n&nbsp;&nbsp;&nbsp; let id: Int\n\n&nbsp;&nbsp;&nbsp; let title: String\n\n&nbsp;&nbsp;&nbsp; let body: String\n\n&nbsp; }\n\n&nbsp;&nbsp;&nbsp; }<\/code><\/pre>\n\n\n\n<p><strong>&nbsp;D.&nbsp;&nbsp;&nbsp; Updating the Timeline Provider<\/strong><\/p>\n\n\n\n<p>The TimelineProvider is responsible for managing the data and timeline of the widget. We&#8217;ll modify it to fetch data from the API and generate the timeline entries.<\/p>\n\n\n\n<p><strong>&nbsp;<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>struct Provider: TimelineProvider {\n\n&nbsp;&nbsp;&nbsp; func placeholder(in context: Context) -&gt; SimpleEntry {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SimpleEntry(date: Date(), posts: &#91;])\n\n&nbsp;&nbsp;&nbsp; }\n\n&nbsp;&nbsp;&nbsp; func getSnapshot(in context: Context,\n\ncompletion: @escaping (SimpleEntry) -&gt; ()) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let entry = SimpleEntry(date: Date(),&nbsp; posts: &#91;])\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; completion(entry)\n\n&nbsp;&nbsp;&nbsp; }\n\n&nbsp;&nbsp;&nbsp; func getTimeline(in context: Context,\n\ncompletion: @escaping\n\n(Timeline&lt;SimpleEntry&gt;) -&gt; ()) {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fetchData { posts in\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let currentDate = Date()\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let refreshDate = Calendar.current.date(byAdding: .minute, value: 1, to: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; currentDate)!\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let entries = posts.prefix(5).enumerated().map { index, post in\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SimpleEntry(\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; date: Calendar.current.date(byAdding: .minute, value: index * 1, to: Date())!,\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; posts: Array(posts.prefix(1))\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let timeline = Timeline(entries: entries, policy: .after(refreshDate))\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; completion(timeline)\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }\n\n&nbsp;&nbsp;&nbsp; }\n\n&nbsp;&nbsp;}\n\nstruct SimpleEntry: TimelineEntry {\n\n&nbsp;&nbsp;&nbsp; let date: Date\n\n&nbsp;&nbsp;&nbsp; let posts: &#91;Post] \/\/ Array of posts\n\n}<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Fetching Data from an API<\/strong><\/li>\n<\/ul>\n\n\n\n<p>Now we\u2019ll fetch data from an API and populate the widget with it. This step involves writing a function to perform the network request and process the response.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>&nbsp;The Provider conforms to the TimelineProvider protocol, which is responsible for managing and providing data to the widget.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>placeholder(in context: Context) -> SimpleEntry :<\/strong><\/li>\n\n\n\n<li>Provides a placeholder entry used to display a preview of the widget when it&#8217;s being edited or when data is not yet available.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -&gt; ()):<\/strong><\/li>\n\n\n\n<li>Provides a snapshot of the widget\u2019s content to display in the widget gallery or on the widget preview.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>getTimeline(in context: Context, completion: @escaping (Timeline&lt;Entry&gt;) &#8211;<a>&gt;(<\/a>))<\/strong><\/li>\n\n\n\n<li>Fetches real data and provides it to the widget\u2019s timeline.<\/li>\n\n\n\n<li>Calls the fetchData function to retrieve posts from the API. It then creates a SimpleEntry with the fetched data and generates a Timeline with this entry, setting the policy to <strong>.atEnd <\/strong>to specify when the widget should be updated next. The completion handler is called with this timeline to update the widget.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Configuring the Widget<\/strong><\/li>\n<\/ul>\n\n\n\n<p>Finally, configure the widget with the timeline provider and the SwiftUI view.<\/p>\n\n\n\n<p>The TrialWidget structure defines the configuration and behavior of the widget. It conforms to the Widget protocol, which is required for creating a widget in iOS.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@main\n\nstruct TrialWidget: Widget {\n\n&nbsp;&nbsp;&nbsp; let kind: String = \"MyWidget\"\n\n&nbsp;&nbsp;&nbsp; var body: some WidgetConfiguration {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StaticConfiguration(kind: kind, provider: Provider()) { entry in\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TrialWidgetEntryView(entry: entry)\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .configurationDisplayName(\"Post Data Widget\")\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .description(\"Displays data from an API.\")\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .supportedFamilies(&#91;.systemLarge])\n\n&nbsp;&nbsp;&nbsp; }\n\n}<\/code><\/pre>\n\n\n\n<p><strong>struct<\/strong> TrialWidget: Widget {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp; <strong>let<\/strong> kind: String = &#8220;MyWidget&#8221;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp; <strong>var<\/strong> body: <strong>some<\/strong> WidgetConfiguration {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StaticConfiguration(kind: kind, provider: Provider()) { entry <strong>in<\/strong><\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TrialWidgetEntryView(entry: entry)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .configurationDisplayName(&#8220;Post Data Widget&#8221;)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .description(&#8220;Displays data from an API.&#8221;)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .supportedFamilies([.systemLarge])<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp; }<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>@main<\/strong>: Marks the entry point of the widget. This annotation indicates that this is the main widget definition to be used by the system.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>var body: some WidgetConfiguration<\/strong>: Defines the configuration of the widget. This is where you set up how the widget will be created and managed by the system.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>StaticConfiguration(kind: kind, provider: Provider()) { entry in<\/strong>: Creates a StaticConfiguration for the widget. This configuration uses a Provider to supply the data for the widget and a closure to define how to display that data using the TrialWidgetEntryView.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>kind: kind<\/strong>: Uses the unique identifier specified earlier.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>provider: Provider()<\/strong>: Specifies the Provider that manages the data and updates for the widget.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>configurationDisplayName<\/strong>: Sets the widget\u2019s name in the gallery.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>description<\/strong>: Provides a brief description of the widget\u2019s functionality.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>supportedFamilies<\/strong>: Specifies which widget sizes are supported.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Handling User Interaction<\/strong><\/li>\n<\/ul>\n\n\n\n<p>We\u2019ve already added interactivity to the widget by using <strong>.widgetURL()<\/strong> in the <strong>TrialWidgetEntryView<\/strong>. This allows the widget to respond when a user taps on it, deep linking into the app.<\/p>\n\n\n\n<p>To handle the deep link in your app, you&#8217;ll need to implement the URL handling in the SceneDelegate or App <a>struct<\/a>, depending on your app&#8217;s structure.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>func application(_ app: UIApplication, open url: URL,\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; options: &#91;UIApplication.OpenURLOptionsKey : Any] = &#91;:]) -&gt; Bool {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if let host = url.host {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if host == \"PostSummary\" {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Navigate to the specific view in your app\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let postTitle = url.lastPathComponent.removingPercentEncoding\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; navigateToPostDetailView(withTitle: postTitle ?? \"\")\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true\n\n&nbsp;&nbsp;&nbsp; }<\/code><\/pre>\n\n\n\n<p>This XML configuration snippet is from an Info.plist file and includes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>NSAppTransportSecurity<\/strong>: Allows the app to load data from any network source, bypassing security restrictions (NSAllowsArbitraryLoads set to true).<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>CFBundleURLTypes<\/strong>: Configures URL schemes for the app. This allows the app to be launched via custom URL schemes (e.g., myapp). CFBundleIdentifier and CFBundleURLName should be replaced with your bundle identifier.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;dict&gt;\n\n&lt;key&gt;CFBundleURLTypes&lt;\/key&gt;\n\n&lt;array&gt;\n\n&lt;dict&gt;\n\n&lt;key&gt;CFBundleIdentifier&lt;\/key&gt;\n\n&lt;string&gt;&lt;\/string&gt;\n\n&lt;key&gt;CFBundleTypeRole&lt;\/key&gt;\n\n&lt;string&gt;Editor&lt;\/string&gt;\n\n&lt;key&gt;CFBundleURLName&lt;\/key&gt;\n\n&lt;string&gt;\"Your Indetifier\u201d&lt;\/string&gt;\n\n&lt;key&gt;CFBundleURLSchemes&lt;\/key&gt;\n\n&lt;array&gt;\n\n&lt;string&gt;myapp&lt;\/string&gt;\n\n&lt;\/array&gt;\n\n&lt;\/dict&gt;\n\n&lt;\/array&gt;\n\n&lt;key&gt;NSAppTransportSecurity&lt;\/key&gt;\n\n&lt;dict&gt;\n\n&lt;key&gt;NSAllowsArbitraryLoads&lt;\/key&gt;\n\n&lt;true\/&gt;\n\n&lt;\/dict&gt;\n\n&lt;\/dict&gt;<\/code><\/pre>\n\n\n\n<p>Here, we\u2019ve included a few screenshots of this demo for your reference.<\/p>\n\n\n\n<p>This screenshot shows the widget we created. the image is static while the text is retrieved from the API.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img fetchpriority=\"high\" decoding=\"async\" width=\"290\" height=\"626\" src=\"https:\/\/blog.200oksolutions.com\/wp-content\/uploads\/2024\/08\/Picture4.png\" alt=\"Screenshot of an iPhone home screen with a custom widget displaying a Latin quote: &quot;sunt aut facere repellat provident occaecati excepturi optio reprehenderit quia et suscipit suscipit recusandae consequuntur expedita et cum...&quot;. The widget also shows the text &quot;200K Solutions&quot; with a checkmark. Below the widget are various app icons including Watch, Contacts, Files, Shortcuts, and others. \" class=\"wp-image-1026\" srcset=\"https:\/\/www.200oksolutions.com\/blog\/wp-content\/uploads\/2024\/08\/Picture4.png 290w, https:\/\/www.200oksolutions.com\/blog\/wp-content\/uploads\/2024\/08\/Picture4-139x300.png 139w\" sizes=\"(max-width: 290px) 100vw, 290px\" \/><\/figure>\n\n\n\n<p>Below screenshot shows the view displayed when tapping on the widget. It presents the post summary controller with the title. Navigation to this page is achieved using a deep link. Since unique identifiers for each piece of data are not feasible in widget extensions, we use the post title for demonstration purposes.<br><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" width=\"266\" height=\"574\" src=\"https:\/\/blog.200oksolutions.com\/wp-content\/uploads\/2024\/08\/Picture5.png\" alt=\"Screenshot of a mobile device with a Latin quote: &quot;sunt aut facere repellat provident occaecati excepturi optio reprehenderit&quot;\" class=\"wp-image-1027\" srcset=\"https:\/\/www.200oksolutions.com\/blog\/wp-content\/uploads\/2024\/08\/Picture5.png 266w, https:\/\/www.200oksolutions.com\/blog\/wp-content\/uploads\/2024\/08\/Picture5-139x300.png 139w\" sizes=\"(max-width: 266px) 100vw, 266px\" \/><\/figure>\n\n\n\n<p>You can find the complete example on <a href=\"https:\/\/github.com\/HiteshM200ok\/iOSWidgetExplorer\">GitHub.<\/a><\/p>\n\n\n\n<p><strong>Conclusion<\/strong><br><br>In this blog, we&#8217;ve explored how to build a dynamic iOS widget that fetches real-time data from an API. We&#8217;ve covered widget configuration, data handling, and deep link navigation. This example lays the groundwork for creating more advanced and interactive widgets, allowing you to enhance your iOS apps with useful, glanceable information right on the home screen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>References<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/developer.apple.com\/documentation\/widgetkit\">Apple Developer Documentation: WidgetKit<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/developer.apple.com\/documentation\/swiftui\">Apple Developer Documentation: SwiftUI<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/developer.apple.com\/documentation\/foundation\/urlsession\">Apple Developer Documentation: URLSession<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/jsonplaceholder.typicode.com\/\">JSONPlaceholder &#8211; Fake Online REST API for Testing<\/a><\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Introduction In our previous blog, we covered widget extensions and their benefits for providing quick, at-a-glance information&hellip;<\/p>\n","protected":false},"author":5,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[75],"tags":[],"class_list":["post-1025","post","type-post","status-publish","format-standard","hentry","category-ios"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Build a Dynamic iOS Widget with API Integration Web Development, Software, and App Blog | 200OK Solutions<\/title>\n<meta name=\"description\" content=\"Build a dynamic iOS widget with API integration. Follow this guide to enhance your app with real-time data directly on the home screen\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Build a Dynamic iOS Widget with API Integration Web Development, Software, and App Blog | 200OK Solutions\" \/>\n<meta property=\"og:description\" content=\"Build a dynamic iOS widget with API integration. Follow this guide to enhance your app with real-time data directly on the home screen\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/\" \/>\n<meta property=\"og:site_name\" content=\"Web Development, Software, and App Blog | 200OK Solutions\" \/>\n<meta property=\"article:published_time\" content=\"2024-08-19T04:03:49+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-12-04T07:44:08+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/blog.200oksolutions.com\/wp-content\/uploads\/2024\/08\/Picture4.png\" \/>\n<meta name=\"author\" content=\"Piyush Solanki\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Piyush Solanki\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Build a Dynamic iOS Widget with API Integration Web Development, Software, and App Blog | 200OK Solutions","description":"Build a dynamic iOS widget with API integration. Follow this guide to enhance your app with real-time data directly on the home screen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/","og_locale":"en_US","og_type":"article","og_title":"Build a Dynamic iOS Widget with API Integration Web Development, Software, and App Blog | 200OK Solutions","og_description":"Build a dynamic iOS widget with API integration. Follow this guide to enhance your app with real-time data directly on the home screen","og_url":"https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/","og_site_name":"Web Development, Software, and App Blog | 200OK Solutions","article_published_time":"2024-08-19T04:03:49+00:00","article_modified_time":"2025-12-04T07:44:08+00:00","og_image":[{"url":"https:\/\/blog.200oksolutions.com\/wp-content\/uploads\/2024\/08\/Picture4.png","type":"","width":"","height":""}],"author":"Piyush Solanki","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Piyush Solanki","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/#article","isPartOf":{"@id":"https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/"},"author":{"name":"Piyush Solanki","@id":"https:\/\/www.200oksolutions.com\/blog\/#\/schema\/person\/e07f6b8e3c9a90ce7b3b09427d26155e"},"headline":"Build a Dynamic iOS Widget with API Integration","datePublished":"2024-08-19T04:03:49+00:00","dateModified":"2025-12-04T07:44:08+00:00","mainEntityOfPage":{"@id":"https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/"},"wordCount":1024,"commentCount":0,"publisher":{"@id":"https:\/\/www.200oksolutions.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/#primaryimage"},"thumbnailUrl":"https:\/\/blog.200oksolutions.com\/wp-content\/uploads\/2024\/08\/Picture4.png","articleSection":["IOS"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/","url":"https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/","name":"Build a Dynamic iOS Widget with API Integration Web Development, Software, and App Blog | 200OK Solutions","isPartOf":{"@id":"https:\/\/www.200oksolutions.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/#primaryimage"},"image":{"@id":"https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/#primaryimage"},"thumbnailUrl":"https:\/\/blog.200oksolutions.com\/wp-content\/uploads\/2024\/08\/Picture4.png","datePublished":"2024-08-19T04:03:49+00:00","dateModified":"2025-12-04T07:44:08+00:00","description":"Build a dynamic iOS widget with API integration. Follow this guide to enhance your app with real-time data directly on the home screen","breadcrumb":{"@id":"https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/#primaryimage","url":"https:\/\/blog.200oksolutions.com\/wp-content\/uploads\/2024\/08\/Picture4.png","contentUrl":"https:\/\/blog.200oksolutions.com\/wp-content\/uploads\/2024\/08\/Picture4.png"},{"@type":"BreadcrumbList","@id":"https:\/\/www.200oksolutions.com\/blog\/building-dynamic-ios-widget-with-api-integration\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.200oksolutions.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Build a Dynamic iOS Widget with API Integration"}]},{"@type":"WebSite","@id":"https:\/\/www.200oksolutions.com\/blog\/#website","url":"https:\/\/www.200oksolutions.com\/blog\/","name":"Web Development, Software, and App Blog | 200OK Solutions","description":"","publisher":{"@id":"https:\/\/www.200oksolutions.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.200oksolutions.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.200oksolutions.com\/blog\/#organization","name":"Web Development Blog | Software Blog | App Blog","url":"https:\/\/www.200oksolutions.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.200oksolutions.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/200oksolutions.com\/blog\/wp-content\/uploads\/2025\/09\/200ok_logo-CGzMrWDu.png","contentUrl":"https:\/\/200oksolutions.com\/blog\/wp-content\/uploads\/2025\/09\/200ok_logo-CGzMrWDu.png","width":500,"height":191,"caption":"Web Development Blog | Software Blog | App Blog"},"image":{"@id":"https:\/\/www.200oksolutions.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.instagram.com\/200ok_solutions\/"]},{"@type":"Person","@id":"https:\/\/www.200oksolutions.com\/blog\/#\/schema\/person\/e07f6b8e3c9a90ce7b3b09427d26155e","name":"Piyush Solanki","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.200oksolutions.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/962a2b0b4db856e6851ec7d838597a0395adcaae9c0091d223de9942a4254461?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/962a2b0b4db856e6851ec7d838597a0395adcaae9c0091d223de9942a4254461?s=96&d=mm&r=g","caption":"Piyush Solanki"},"description":"Piyush is a seasoned PHP Tech Lead with 10+ years of experience architecting and delivering scalable web and mobile backend solutions for global brands and fast-growing SMEs. He specializes in PHP, MySQL, CodeIgniter, WordPress, and custom API development, helping businesses modernize legacy systems and launch secure, high-performance digital products. He collaborates closely with mobile teams building Android &amp; iOS apps , developing RESTful APIs, cloud integrations, and secure payment systems using platforms like Stripe, AWS S3, and OTP\/SMS gateways. His work extends across CMS customization, microservices-ready backend architectures, and smooth product deployments across Linux and cloud-based environments. Piyush also has a strong understanding of modern front-end technologies such as React and TypeScript, enabling him to contribute to full-stack development workflows and advanced admin panels. With a successful delivery track record in the UK market and experience building digital products for sectors like finance, hospitality, retail, consulting, and food services, Piyush is passionate about helping SMEs scale technology teams, improve operational efficiency, and accelerate innovation through backend excellence and digital tools.","url":"https:\/\/www.200oksolutions.com\/blog\/author\/piyush\/"}]}},"_links":{"self":[{"href":"https:\/\/www.200oksolutions.com\/blog\/wp-json\/wp\/v2\/posts\/1025","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.200oksolutions.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.200oksolutions.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.200oksolutions.com\/blog\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/www.200oksolutions.com\/blog\/wp-json\/wp\/v2\/comments?post=1025"}],"version-history":[{"count":6,"href":"https:\/\/www.200oksolutions.com\/blog\/wp-json\/wp\/v2\/posts\/1025\/revisions"}],"predecessor-version":[{"id":1036,"href":"https:\/\/www.200oksolutions.com\/blog\/wp-json\/wp\/v2\/posts\/1025\/revisions\/1036"}],"wp:attachment":[{"href":"https:\/\/www.200oksolutions.com\/blog\/wp-json\/wp\/v2\/media?parent=1025"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.200oksolutions.com\/blog\/wp-json\/wp\/v2\/categories?post=1025"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.200oksolutions.com\/blog\/wp-json\/wp\/v2\/tags?post=1025"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}