<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: VladislavMokrov</title>
    <description>The latest articles on Forem by VladislavMokrov (@vladosius).</description>
    <link>https://forem.com/vladosius</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1124790%2Fca752898-a693-423f-be6a-ce9ef6ef1456.jpg</url>
      <title>Forem: VladislavMokrov</title>
      <link>https://forem.com/vladosius</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/vladosius"/>
    <language>en</language>
    <item>
      <title>Implementing location search by address into the iOS app. Step-by-Step Guide</title>
      <dc:creator>VladislavMokrov</dc:creator>
      <pubDate>Sun, 23 Jul 2023 14:19:22 +0000</pubDate>
      <link>https://forem.com/vladosius/implementing-location-search-by-address-into-the-ios-app-step-by-step-guide-3g6a</link>
      <guid>https://forem.com/vladosius/implementing-location-search-by-address-into-the-ios-app-step-by-step-guide-3g6a</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
In this article we take a look at the fun process of implementing location search by address in an iOS app. If you’re developing an app with maps or location-related functionality, this guide will help you get specific coordinates based on the address the user enters in the searchBar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Import into your file&lt;/strong&gt;&lt;br&gt;
import CoreLocation&lt;br&gt;
import MapKit&lt;/p&gt;

&lt;p&gt;What is the difference between CoreLocation and MapKit?&lt;br&gt;
CoreLocation is the processing of location data. It uses all available device components, including cellular equipment, Wi-Fi, Bluetooth, GPS, barometer and magnetometer.&lt;br&gt;
MapKit is all about visual operations such as map rendering, route directions, address finding and user-friendly operations. Anyway, who wants to type in latitude and instead of a readable address?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Properties that will be needed&lt;/strong&gt;&lt;br&gt;
private lazy var completer = MKLocalSearchCompleter()&lt;/p&gt;

&lt;p&gt;private lazy var searchResults: [(title: String?, subtitle: String?, coordinate: CLLocationCoordinate2D?)] = []&lt;/p&gt;

&lt;p&gt;private var searchCompletion: (([(title: String?, subtitle: String?, coordinate: CLLocationCoordinate2D?)]) -&amp;gt; Void)?&lt;/p&gt;

&lt;p&gt;private var userRegionCoordinate: CLLocationCoordinate2D?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Problem with geocodeAddressString from CLGeocoder&lt;/strong&gt;&lt;br&gt;
At the beginning of development, I decided to use the geocodeAddressString method from CLGeocoder in the searchAddressesForText method. However, I ran into a certain problem. This method always returned only one address with coordinates, not providing a complete list of addresses to choose from. For example, in some countries there may be many streets with the same name. If I passed such a string to the method, I received only one CLPlacemark representing a street in a random city. This limitation was not suitable for my application, so I needed to find an alternative solution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func searchAddressesForText(_ text: String, completion: @escaping ([String]) -&amp;gt; Void) {
        let region = CLCircularRegion(center: userRegionCoordinate, radius: 30000, identifier: "SearchRegion")

        let geocoder = CLGeocoder()
        geocoder.geocodeAddressString(text, in: region, completionHandler: { (placemarks, error) in
            var addresses: [String] = []
            if let placemarks = placemarks {
                for placemark in placemarks {
                    if let thoroughfare = placemark.thoroughfare, let subThoroughfare = placemark.subThoroughfare {
                        let address = "\(thoroughfare), \(subThoroughfare)"
                        addresses.append(address)
                    } else if let thoroughfare = placemark.thoroughfare {
                        let address = "\(thoroughfare)"
                        addresses.append(address)
                    }
                }
            }
            completion(addresses)
        })
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Using MKLocalSearchCompleter&lt;/strong&gt;&lt;br&gt;
I later discovered that MKLocalSearchCompleter can solve this problem. It provides multiple addresses by closest match, allowing the user to select the correct address from the list. However, this solution has the disadvantage that it does not provide coordinates for each address. Instead, the user must select one of the addresses and then call the searchCoordinatesForAddress method to get the coordinates of the selected address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func searchAddressesForText(_ text: String,
                            completion: @escaping ([(title: String?,
                                                     subtitle: String?,
                                                     coordinate: CLLocationCoordinate2D?)]) -&amp;gt; Void) {
    completer.delegate = self
    completer.queryFragment = text

    if let userRegionCoordinate = self.userRegionCoordinate {
        let region = MKCoordinateRegion(center: userRegionCoordinate, latitudinalMeters: 5000, longitudinalMeters: 5000)
        completer.region = region
    }

    searchCompletion = completion
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use MKLocalSearchCompleter, I have created an instance of MKLocalSearchCompleter and set up its delegate. I then set the search text and region to get the appropriate results. After updating the search results, I retrieve the address list and pass it to the completion unit for further processing or display.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. MKLocalSearchCompleterDelegate&lt;/strong&gt;&lt;br&gt;
To overcome the limitation of no coordinates for addresses obtained with MKLocalSearchCompleter, I used MKLocalSearchCompleter to get a list of addresses and then used MKLocalSearch to get the coordinates of the selected address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extension SomeViewController: MKLocalSearchCompleterDelegate {
    public func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
        searchResults = completer.results.compactMap { result in
            let street = result.title
            let subtitle = result.subtitle
            let searchRequest = MKLocalSearch.Request(completion: result)
            let coordinate = searchRequest.region.center

            //If you want to exclude any result
            let isRelevant = number != "find near me"
            guard isRelevant else {
                return nil
            }
            return (title: street, subtitle: number, coordinate: coordinate)
        }
        searchCompletion?(searchResults)
    }

    public func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
        searchResults = []
        searchCompletion?(searchResults)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. Getting coordinates&lt;/strong&gt;&lt;br&gt;
The user is given a list of addresses obtained with MKLocalSearchCompleter and can select one of them. When the user selects an address, I pass it to the searchCoordinatesForAddress method to retrieve the corresponding coordinates using MKLocalSearch. In this way, I combine the advantages of both approaches and get the full functionality of location search by address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func searchCoordinatesForAddress(_ address: [(title: String?, subtitle: String?)],
                                 completion: @escaping ([(title: String?,
                                                          subtitle: String?,
                                                          coordinate: CLLocationCoordinate2D?)]?) -&amp;gt; Void) {
    let searchRequest = MKLocalSearch.Request()
    let entireAddress = address.title + " " + address.subtitle
    searchRequest.naturalLanguageQuery = entireAddress

    let search = MKLocalSearch(request: searchRequest)
    search.start { response, error in
        if let response = response,
            let firstPlacemark = response.mapItems.first?.placemark {
            let coordinate = firstPlacemark.coordinate
            completion(title: address.title, subtitle: address.subtitle, coordinate: coordinate)
        } else {
            completion(nil)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7. Cancel the search if it is no longer required&lt;/strong&gt;&lt;br&gt;
For example, if the user has typed an address and decides to close the screen immediately.&lt;br&gt;
Or when entering each new character into searchBar in method:&lt;br&gt;
&lt;em&gt;func searchBar(&lt;/em&gt; searchBar: UISearchBar, textDidChange searchText: String)_&lt;br&gt;
You must cancel the search with this method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func cancelSearchAddresses() {
     if completer.isSearching {
         completer.cancel()
     }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
In this article we looked at the process of implementing location search functionality by address in an iOS application. We found a problem using the geocodeAddressString method from CLGeocoder, which returns only one address, and a solution to this problem using MKLocalSearchCompleter, which provides multiple addresses but no coordinates. We also looked at a combined approach which allows us to get both a list of addresses and the corresponding coordinates of the selected address.&lt;/p&gt;

&lt;p&gt;I hope this guide was useful for you and helped you solve the problem of finding a location by address in your iOS app.&lt;br&gt;
If you have any further questions, please feel free to ask.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>maps</category>
    </item>
    <item>
      <title>All about Silent Push Notifications. Step-by-Step Guide</title>
      <dc:creator>VladislavMokrov</dc:creator>
      <pubDate>Sun, 23 Jul 2023 10:23:45 +0000</pubDate>
      <link>https://forem.com/vladosius/all-about-silent-push-notifications-step-by-step-guide-3137</link>
      <guid>https://forem.com/vladosius/all-about-silent-push-notifications-step-by-step-guide-3137</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
In this article I would like to share my experience of implementing Silent Push Notifications in an iOS app. The purpose of using Silent Push Notifications was to solve the problem of some services going to sleep when the phone is idle for a long period of time. Or for example, if you have a messenger app and you want the user to be able to access new/updated content and not have to wait for it to download. Silent Push Notifications allowed us to activate the app once every 21 minutes (the minimum value we picked up so that Apple would not grant a temporary ban) and run the services in the background to update.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Silent Push Notifications&lt;/strong&gt;&lt;br&gt;
Provide the ability to update the content of your application, make API calls and perform background tasks. They are sent without activating screen beeping or other visible notifications&lt;br&gt;
(In fact, the application goes into an “active” state, and is generally no different from a normal startup. Navigation will function and screens will initialise, although they will not be visible on the screen. All actions called in the “didFinishLaunchingWithOptions” method will also be executed).&lt;br&gt;
Silent push notifications wake up your application in the background, allowing time to download data from the server and perform tasks in the background.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Setting up Silent Push Notifications&lt;/strong&gt;&lt;br&gt;
First, you need to set up support for Silent Push Notifications in your application. Here is a brief overview of the steps you need to follow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.1&lt;/strong&gt; Developer Portal&lt;br&gt;
Go to the Developer Portal on Apple’s website and make sure Background Modes and Background Fetch support is enabled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.2&lt;/strong&gt; Provisioning Profile&lt;br&gt;
Ensure that the Provisioning Profile (linked to your App ID) includes support for Background Modes and Background Fetch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.3&lt;/strong&gt; Enabling Remote Notifications&lt;br&gt;
In your project in Xcode, open the file AppDelegate.swift and add the following code to the method &lt;code&gt;application(_:didFinishLaunchingWithOptions:)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Registration to receive notifications

let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
    if granted {
        DispatchQueue.main.async {
            UIApplication.shared.registerForRemoteNotifications()
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1.4&lt;/strong&gt; Signing&amp;amp;Capabilities&lt;br&gt;
Here you need to give permission to use push notifications&lt;br&gt;
Scroll to the bottom. And tick the box for “Remote notifications”. Check the rest depending on your needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kp8KFe7s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2k1u7sd9ovtcqyvoz8r0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kp8KFe7s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2k1u7sd9ovtcqyvoz8r0.jpg" alt="Image description" width="800" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Handling Silent Push Notifications&lt;/strong&gt;&lt;br&gt;
After setting up Silent Push Notifications, you’ll need a handler that will respond to receiving such notifications and trigger a some service. Here’s a sample code to add to your AppDelegate.swift&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func application(_ application: UIApplication, 
     didReceiveRemoteNotification userInfo: [AnyHashable: Any], 
     fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -&amp;gt; Void) {
        // Silent Push Notification processing
    if let silentNotification = userInfo["aps"] as? [String: AnyObject], 
       silentNotification["content-available"] as? Int == 1 {
        // Launch of a some service
        SomeManager.shared.startUpdatingAnything()
    }
        // Ending a background operation
    completionHandler(.noData)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the completion handler&lt;br&gt;
You only have 30 seconds to execute the background request and you should call the completionHandler on completion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Backend&lt;/strong&gt;&lt;br&gt;
All the things you should tell your backend developers&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.1&lt;/strong&gt; You must tell the backend which body to send, you can add additional fields at your discretion.&lt;br&gt;
For notifications to be silent, you must specify “content-available” : 1.&lt;/p&gt;

&lt;p&gt;You can read more about it &lt;a href="https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.2&lt;/strong&gt; If you want to check your notifications without a backend like I do. You will need an application that emulates the backend to check.&lt;/p&gt;

&lt;p&gt;I used &lt;a href="https://github.com/onmyway133/PushNotifications"&gt;PushNotifications&lt;/a&gt;.&lt;br&gt;
(You can skip this point and go straight to 3.2.1)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update!&lt;/strong&gt; On the day I published this article, apple introduced a new tool for push notifications 😅&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.2.1 &lt;a href="https://idmsa.apple.com/IDMSWebAuth/signin?appIdKey=2bd7197b69c47f19a2230102e44970030ca15dae4afedcf593984ff1ae03e874&amp;amp;path=%2Fdashboard%2Fnotifications&amp;amp;rv=4"&gt;Push Notifications Console&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
“The new Push Notifications Console makes it easy to send test notifications to Apple devices through the Apple Push Notification service (APNs). You can access logs that provide insights into the delivery process and leverage tools to generate and validate tokens.” — Taken from Apple’s official &lt;a href="https://developer.apple.com/notifications/push-notifications-console/"&gt;website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7ztiSIdN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ccozeaptohlrdfxaet7a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7ztiSIdN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ccozeaptohlrdfxaet7a.jpg" alt="Image description" width="800" height="520"&gt;&lt;/a&gt;&lt;br&gt;
Taken from Apple’s official &lt;a href="https://developer.apple.com/notifications/push-notifications-console/"&gt;website&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will not need the p8 file for Push Notifications Console. You simply log in to your account and start testing. It’s also very convenient to use push notifications logging.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.3&lt;/strong&gt; Registration token&lt;br&gt;
A registration token is required to send remote notifications.&lt;/p&gt;

&lt;p&gt;In order to send notifications to remote devices, your application must receive a registration token that the APNs (Apple Push Notification service) uses to deliver notifications to a specific device. The registration token is a unique identifier tied to the device and your app. When your app is launched, it communicates with APNs to receive a registration token, which can then be sent to your server. Your server uses this token to send notifications to the relevant device.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func application(_ application: UIApplication,
                 didRegisterForRemoteNotificationsWithDeviceToken deviceToken:Data) {
   let pushToken = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
   self.yourPushNotificationsService.pushTokenDidReceived(pushNotificationToken: pushToken)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have a registration token for a particular user, you can send notifications to their remote device via your server, a third-party service (PushNotifications) or Firebase Cloud Messaging.&lt;/p&gt;

&lt;p&gt;The process of receiving a token and sending notifications is shown in the diagram below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AzAx65AI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ifegi13762lceihevxf5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AzAx65AI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ifegi13762lceihevxf5.jpg" alt="Image description" width="800" height="421"&gt;&lt;/a&gt;&lt;br&gt;
Source: &lt;a href="https://betterprogramming.pub"&gt;https://betterprogramming.pub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.4&lt;/strong&gt; Download the .p8 file&lt;br&gt;
&lt;strong&gt;a.&lt;/strong&gt; If your app already has normal push notifications, request the p8 key from the person in charge of push notifications on the backend or a senior/lead iOS developer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;b.&lt;/strong&gt; If you are setting up push notifications for the first time, the following instructions are for you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to Apple developer account and go to Certificates, Identifiers &amp;amp; Profiles&lt;/li&gt;
&lt;li&gt;Go to Keys section and click on a new key using Add button(+).&lt;/li&gt;
&lt;li&gt;Choose a unique name for key and select Apple Push Notification service(APNs) checkbox. Click continue and then confirm.&lt;/li&gt;
&lt;li&gt;Note and save the key ID. Click Download to generate and save the key.
!&lt;strong&gt;!! Please note&lt;/strong&gt; you have to save the key in a secured place because you can’t download key more than once. Do not rename Auth key file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;4. After installing the app on your physical device&lt;/strong&gt;&lt;br&gt;
When you install the app be sure to check whether it has Background App Refresh enabled&lt;/p&gt;

&lt;p&gt;Settings &amp;gt; (scroll down) &amp;gt; Your app &amp;gt; Background App Refresh (enable)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Problems and solutions&lt;/strong&gt;&lt;br&gt;
In the process of implementing Silent Push Notifications, I have encountered a few problems which may be useful to you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.1&lt;/strong&gt; Apple’s restrictions&lt;br&gt;
Apple has a strict limit on how often Silent Push Notifications are sent. If several Silent Push Notifications are sent in a row, they may stop reaching the user. To avoid this problem, I used a backend timer to ensure that Silent Push Notifications are only sent once every 21 minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.2&lt;/strong&gt; Error handling&lt;br&gt;
It is important to handle possible errors when processing Silent Push Notifications. For example, if a some service is already active, new Silent Push Notifications should be ignored to avoid having to run the service continuously and using resources unnecessarily.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.3&lt;/strong&gt; Optimise battery usage&lt;br&gt;
Running some services can consume a significant amount of battery power. To minimise this, I have set a limit on the time the service will run after each Silent Push Notification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is very important to note the following points:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.4&lt;/strong&gt; The Silent Push does not work in “low power mode”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.5&lt;/strong&gt; The treatment of the silent-push system depends on several factors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Amount of free memory available: when you close an application, the system creates a snapshot of the memory used and assigns points to the Silent Push processing speed. If your application is training a machine learning model or using more than 400 MB of memory, the system may refuse to process the push notification. It is therefore recommended that you try to minimise resource usage and free up memory when switching to background mode.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Battery charge level.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Frequency of push notifications: the system can handle silent push notifications no more frequently than once every 20 minutes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Time of day: the system can change its attitude towards handling push notifications depending on the time of day.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Phone charging status: if the device is on charge, the system may be more prone to handle silent-push.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;App crash: if your app crashes, the system will probably not handle the silent-push and may assign penalty points.&lt;br&gt;
So when you put your phone on charge and get your first silent push the next morning, the system will gradually increase the likelihood of handling push notifications and reduce the penalty points over time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
The use of silent Push notifications in the app has solved the problem of some services falling asleep when the phone is left for extended periods. Launching the service every 21 minutes after receiving a silent Push notification updates the data in the app, providing a better experience and usability.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Share your thoughts about the article. Your comments will help me expand on this research and provide additional material on the topic of the article. This will make it more useful.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I would like to dedicate my first technical article to my mentor. I want to express my sincere gratitude for your patience, politeness, and consistency while I was a junior developer.&lt;br&gt;
Keep up the great work!&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>mobile</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
