iOS Tutorial Background Fetch (Downloads)

Background fetch feature allows applications to run for a short period of time (up to 30 seconds) while in the background.

The steps required to use this service are:
1. Add the fetch mode declaration:
B4X:
#PlistExtra: <key>UIBackgroundModes</key><array><string>fetch</string></array>
2. Download the attached zip file and copy main.m to <project>\Files\Special.
3. Set the minimum interval (measured in seconds) with this code:
B4X:
Dim no As NativeObject = App
no.RunMethod("setMinimumBackgroundFetchInterval:", Array(0)) '0 = minimum interval

4. Handle the Application_FetchDownload event. It will be raised whenever your app is waked by this service:
B4X:
Private Sub Application_FetchDownload
   Log("FetchDownload")
   Dim ln As Notification
   ln.Initialize(DateTime.Now)
   ln.AlertBody = "Fetch download..."
   ln.PlaySound = True
   ln.Register
End Sub

5. When you completed the task you should run this code:
B4X:
Dim no As NativeObject = App
   no = no.GetField("delegate")
   no.RunMethod("completeFetch:", Array(0))
Note that you can run this code from any sub you like (JobDone for example).
The number (0 in the code above) is the UIBackgroundFetchResult. 0 means NewData.
The other values are listed here: https://developer.apple.com/library...ml#//apple_ref/c/tdef/UIBackgroundFetchResult

From my tests, with the minimum interval set to 0, the OS wakes the app every 10 - 15 minutes (when the screen is on).

B4X:
#Region  Project Attributes
   #ApplicationLabel: Background Fetch
   #Version: 1.0.0
   #iPhoneOrientations: Portrait, LandscapeLeft, LandscapeRight
   #iPadOrientations: Portrait, LandscapeLeft, LandscapeRight, PortraitUpsideDown
   #PlistExtra: <key>UIBackgroundModes</key><array><string>fetch</string></array>
#End Region

Sub Process_Globals
   Public App As Application
   Public NavControl As NavigationController
   Private Page1 As Page

End Sub

Private Sub Application_Start (Nav As NavigationController)
   NavControl = Nav
   Page1.Initialize("Page1")
   Page1.Title = "Page 1"
   Page1.RootPanel.Color = Colors.White
   NavControl.ShowPage(Page1)
   Dim no As NativeObject = App
   no.RunMethod("setMinimumBackgroundFetchInterval:", Array(0))
End Sub

Private Sub Application_FetchDownload
   Log("FetchDownload")
   Dim ln As Notification
   ln.Initialize(DateTime.Now)
   ln.AlertBody = "Fetch download..."
   ln.PlaySound = True
   ln.Register

   Dim no As NativeObject = App
   no = no.GetField("delegate")
   no.RunMethod("completeFetch:", Array(0))
End Sub
 

Attachments

  • main.zip
    516 bytes · Views: 991
Last edited:

Daniel Garcia

New Member
Licensed User
Longtime User
HI,

In the simulator, works application_fetchdownload?
I copy the example, but, not work, never handle the application_fechdownload event.... I replace the main.h from "Program Files\Anywhere Software\B4i\Project"..
I can not be doing wrong :(

my code:

B4X:
'Code module
#Region  Project Attributes
   #ApplicationLabel: Background Fetch
   #Version: 1.0.0
   #iPhoneOrientations: Portrait, LandscapeLeft, LandscapeRight
   #iPadOrientations: Portrait, LandscapeLeft, LandscapeRight, PortraitUpsideDown
   #PlistExtra: <key>UIBackgroundModes</key><array><string>fetch</string></array>
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
    Public App As Application
    Public NavControl As NavigationController
    Private Page1 As Page
    Dim RL As ReleaseLogger
   
End Sub

Sub Application_Start (Nav As NavigationController)
   
    RL.Initialize("172.30.4.87", 54323) 'load inetwork library
   
   NavControl = Nav
   Page1.Initialize("Page1")
   Page1.Title = "Page 1"
   Page1.RootPanel.Color = Colors.White
   NavControl.ShowPage(Page1)
   Dim no As NativeObject = App
   no.RunMethod("setMinimumBackgroundFetchInterval:", Array(0))
      Log("Starter")
End Sub



Private Sub application_fetchdownload
   Log("FetchDownload")
   Dim ln As Notification
   ln.Initialize(DateTime.Now)
   ln.AlertBody = "Fetch download..."
   ln.PlaySound = True
   ln.Register
   Dim no As NativeObject = App
   no = no.GetField("delegate")
   no.RunMethod("completeFetch:", Array(0))
End Sub

can anybody help me...please!!!!

Thank's
 

Daniel Garcia

New Member
Licensed User
Longtime User
HI,

In the simulator, works application_fetchdownload?
I copy the example, but, not work, never handle the application_fechdownload event.... I replace the main.h from "Program Files\Anywhere Software\B4i\Project"..
I can not be doing wrong :(

my code:

B4X:
'Code module
#Region  Project Attributes
   #ApplicationLabel: Background Fetch
   #Version: 1.0.0
   #iPhoneOrientations: Portrait, LandscapeLeft, LandscapeRight
   #iPadOrientations: Portrait, LandscapeLeft, LandscapeRight, PortraitUpsideDown
   #PlistExtra: <key>UIBackgroundModes</key><array><string>fetch</string></array>
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
    Public App As Application
    Public NavControl As NavigationController
    Private Page1 As Page
    Dim RL As ReleaseLogger
  
End Sub

Sub Application_Start (Nav As NavigationController)
  
    RL.Initialize("172.30.4.87", 54323) 'load inetwork library
  
   NavControl = Nav
   Page1.Initialize("Page1")
   Page1.Title = "Page 1"
   Page1.RootPanel.Color = Colors.White
   NavControl.ShowPage(Page1)
   Dim no As NativeObject = App
   no.RunMethod("setMinimumBackgroundFetchInterval:", Array(0))
      Log("Starter")
End Sub



Private Sub application_fetchdownload
   Log("FetchDownload")
   Dim ln As Notification
   ln.Initialize(DateTime.Now)
   ln.AlertBody = "Fetch download..."
   ln.PlaySound = True
   ln.Register
   Dim no As NativeObject = App
   no = no.GetField("delegate")
   no.RunMethod("completeFetch:", Array(0))
End Sub

can anybody help me...please!!!!

Thank's

All right!!

I open the project in Xcode (Mac server -> projects uploaded -> xxx -> B4iproyect ...) in xcode can simulate fetch in background (debug -> Background Simulate Fecht), also you can run the app background (Product -> Scheme -> Edit Scheme (check the background fetch)).

It is very fast to test the background processes!!!

Thank's
 

Descartex

Well-Known Member
Licensed User
Longtime User
Hi
I'm having problems with fetch download implementation.
I followed all the steps on the first post, adding this line to the main:
B4X:
    #PlistExtra: <key>UIBackgroundModes</key><array><string>fetch</string></array>
and this:
B4X:
Nav.NavigationBarVisible=False
    Nav.ToolBarVisible=False
   
    App.RegisterUserNotifications(True, True, True) 'request permission for notifications
    App.ApplicationIconBadgeNumber = 0
   
   
    GlobalVars.NavControl = Nav
    Dim no As NativeObject = App
    no.RunMethod("setMinimumBackgroundFetchInterval:", Array(5)) '5 seconds

This is the code for the FetchDownload

B4X:
Private Sub Application_FetchDownload
    Log("FetchDownload")
    Dim ln As Notification
    ln.Initialize(DateTime.Now)
    ln.AlertBody = "fetch download..."
    ln.PlaySound = True
    ln.Register
End Sub

Also i changed the main.m file on my B4i installation folder as @Erel told on another post.

But the problem is that the notification never arrives...

Help me please a little :(
 

Descartex

Well-Known Member
Licensed User
Longtime User
I've already done it, and, on release mode, i achieved to run the notification, but with an erratic behaviour. I mean.
Sometimes it raises after 10 minutes, others after 13 minutes, others 16, does not follows a pattern.
On the Android version of the app, i can do the background task with no problem.
I only need to check a variable from my server and, if changed, raise a notification to the user only when app is not in "foreground mode".
Is it a way to make a task run background with a reasonable pattern?

Cupertino boys sometimes are quite silly... they usually runs my patience out...

Thanks a lot.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Sometimes it raises after 10 minutes, others after 13 minutes, others 16, does not follows a pattern.
This is exactly how the background fetch mode is expected to work.

Is it a way to make a task run background with a reasonable pattern?
Sounds to me that you need to use push notifications instead.
 

Descartex

Well-Known Member
Licensed User
Longtime User
Erel said:
This is exactly how the background fetch mode is expected to work.
I readed later your post with the results of setting the minimum to 0.

Erel said:
Sounds to me that you need to use push notifications instead.
I suspected it.. Thanks a lot.
 

valentino s

Active Member
Licensed User
Longtime User
I want to thank you all. I've added all commands to let it work, and this is a final working app (demo).
 

Attachments

  • notifications and background download.zip
    5.6 KB · Views: 485

MarcoRome

Expert
Licensed User
Longtime User
Hello everyone, I tried the example of @valentino s and that of @Erel, but what should happen?
I compiled in release mode, tried to close the app and nothing happens, then tried to put the app in the backgound and the same nothing happens.
I don't receive any message or notification.
Where i'm wrong
Thank you
Marco

B4X:
Code module
#Region  Project Attributes
    #ApplicationLabel: Notifiche BackGround
    'Orientation possible values: Portrait, LandscapeLeft, LandscapeRight and PortraitUpsideDown
    #iPhoneOrientations: Portrait, LandscapeLeft, LandscapeRight
    #iPadOrientations: Portrait, LandscapeLeft, LandscapeRight, PortraitUpsideDown
    #Target: iPhone, iPad
    #MinVersion: 7
    #PlistExtra: <key>UIBackgroundModes</key><array><string>fetch</string></array>

#End Region

'Per Sviluppo non distribuzione
#CertificateFile: ios_development.cer
#ProvisionFile: Ultimo.mobileprovision

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
    Public App As Application
    Public NavControl As NavigationController
    Private Page1 As Page
    Dim ln As Notification

    Private Button1 As Button
    Private WebView1 As WebView
End Sub

Private Sub Application_Start (Nav As NavigationController)

    NavControl = Nav
    Page1.Initialize("Page1")
    Page1.Title = "Page 1"
    Page1.RootPanel.Color = Colors.White
    Page1.RootPanel.LoadLayout("main")
    
    NavControl.ShowPage(Page1)

    App.RegisterUserNotifications(True,True,True)
    App.ApplicationIconBadgeNumber=0

    Dim no As NativeObject = App
    no.RunMethod("setMinimumBackgroundFetchInterval:", Array(35)) 'minimunm >30 seconds  (PS: APP in BACKGROUND !)
    
End Sub

Private Sub Page1_Resize(Width As Int, Height As Int)
    
End Sub

Private Sub Application_Background
    Log("Sono in BackGround")
End Sub


Private Sub Application_FetchDownload
    App.ApplicationIconBadgeNumber=33
    'Log ("parte " & DateTime.Now)
   Dim Job1 As HttpJob
   Job1.Initialize("dealoftheday", Me)
   Job1.Download("http://www.iusondemand.it/exvoto/home.txt")
End Sub

Sub JobDone (Job As HttpJob)
    'Log ("done "  & DateTime.Now)
    If Job.Success = True Then
        Select Job.JobName
            Case "dealoftheday"
                If Job.GetString.Contains("a") Then
                    If ln.IsInitialized = False Then
                        ln.Initialize(DateTime.Now)
                        ln.AlertBody = Job.GetString & DateTime.Now
                        ln.PlaySound = True
                        ln.IconBadgeNumber = 1
                        ln.Register

                        App.ApplicationIconBadgeNumber=2
                      
                        Dim no As NativeObject = App
                        no = no.GetField("delegate")
                        no.RunMethod("completeFetch:", Array(0))
                    End If
                End If
        End Select
    End If
    Job.Release
End Sub

Private Sub Application_Foreground
    'Log ("azzera "  & DateTime.Now)
    App.ApplicationIconBadgeNumber=0
End Sub

Sub Button1_Click
    WebView1.LoadHtml("test " & DateTime.Now)
End Sub
 

MarcoRome

Expert
Licensed User
Longtime User
Note that you need to call completeFetch in all cases. You can simplify the code with a single resumable sub.
Set the minimum interval to 0.
Don't kill the app with a swipe.
Leave the phone connected to the charger.

The expected result is that Application_FetchDownloads runs once in a while.

It works, after restarting the device
 

MarcoRome

Expert
Licensed User
Longtime User
From this morning i saw the notification only once. Then nothing happened.


1. Don't kill the app with a swipe. As you can see, the app is still in the background from this morning.

upload_2018-6-7_17-5-51.png


2. The phone is connected to the charger.

3.This is code App
B4X:
'Code module
#Region  Project Attributes
    #ApplicationLabel: B4i Background
    #Version: 1.0.0
    'Orientation possible values: Portrait, LandscapeLeft, LandscapeRight and PortraitUpsideDown
    #iPhoneOrientations: Portrait, LandscapeLeft, LandscapeRight
    #iPadOrientations: Portrait, LandscapeLeft, LandscapeRight, PortraitUpsideDown
    #Target: iPhone, iPad
    #ATSEnabled: True
    #MinVersion: 7
#End Region


'Link --> https://www.b4x.com/android/forum/threads/background-fetch-downloads.56022/#content

'Per Sviluppo non distribuzione
#CertificateFile: ios_development.cer
#ProvisionFile: Ultimo.mobileprovision

#PlistExtra: <key>UIBackgroundModes</key><array><string>fetch</string></array>

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
    Public App As Application
    Public NavControl As NavigationController
    Private Page1 As Page

End Sub

Private Sub Application_Start (Nav As NavigationController)
    'SetDebugAutoFlushLogs(True) 'Uncomment if program crashes before all logs are printed.
    NavControl = Nav
    Page1.Initialize("Page1")
    Page1.Title = "Page 1"
    Page1.RootPanel.Color = Colors.White
    NavControl.ShowPage(Page1)
    
    Dim no As NativeObject = App
    no.RunMethod("setMinimumBackgroundFetchInterval:", Array(0)) '0 = minimum interval
End Sub

Private Sub Application_FetchDownload
    Log("FetchDownload")
    Dim ln As Notification
    ln.Initialize(DateTime.Now)
    ln.AlertBody = "Fetch download..."
    ln.PlaySound = True
    ln.Register
    
    Dim no As NativeObject = App
    no = no.GetField("delegate")
    no.RunMethod("completeFetch:", Array(0))
End Sub

Private Sub Page1_Resize(Width As Int, Height As Int)
    
End Sub

Private Sub Application_Background
    
End Sub

Where i wrong ?

P.S. The device is iPhone 6s / iOS 11.3
Thank you
 

MarcoRome

Expert
Licensed User
Longtime User
I tried again with the following code in debug mode:

B4X:
'Code module
#Region  Project Attributes
    #ApplicationLabel: B4i Background
    #Version: 1.0.0
    'Orientation possible values: Portrait, LandscapeLeft, LandscapeRight and PortraitUpsideDown
    #iPhoneOrientations: Portrait, LandscapeLeft, LandscapeRight
    #iPadOrientations: Portrait, LandscapeLeft, LandscapeRight, PortraitUpsideDown
    #Target: iPhone, iPad
    #ATSEnabled: True
    #MinVersion: 7
#End Region



'Link --> https://www.b4x.com/android/forum/threads/background-fetch-downloads.56022/#content

'Per Sviluppo non distribuzione
#CertificateFile: ios_development.cer
#ProvisionFile: Ultimo.mobileprovision

#PlistExtra: <key>UIBackgroundModes</key><array><string>fetch</string></array>

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
    Public App As Application
    Public NavControl As NavigationController
    Private Page1 As Page
    Private hd As HUD

End Sub

Private Sub Application_Start (Nav As NavigationController)
    'SetDebugAutoFlushLogs(True) 'Uncomment if program crashes before all logs are printed.
    NavControl = Nav
    Page1.Initialize("Page1")
    Page1.Title = "Page 1"
    Page1.RootPanel.Color = Colors.White
    NavControl.ShowPage(Page1)
    
    'For Notification
    App.RegisterUserNotifications(True, True, True) 'request permission for notifications
    App.ApplicationIconBadgeNumber = 0
    'check whether the app was started from a notification
    If App.LaunchOptions.IsInitialized Then
        Dim ln As Notification  = App.LaunchOptions.Get("UIApplicationLaunchOptionsLocalNotificationKey")
        If ln.IsInitialized Then
            'hd.ToastMessageShow("Application was started from a notification: " & ln.AlertBody, True)
            Log("Application was started from a notification")
        End If
    End If

    Dim no As NativeObject = App
    no.RunMethod("setMinimumBackgroundFetchInterval:", Array(0)) '0 = minimum interval
End Sub

Private Sub Application_FetchDownload
    Log("FetchDownload")
    Dim ln As Notification
    ln.Initialize(DateTime.Now)
    ln.IconBadgeNumber = 1
    ln.AlertBody = "Fetch download..."
    ln.PlaySound = True
    ln.Register
    
    
    Dim no As NativeObject = App
    no = no.GetField("delegate")
    no.RunMethod("completeFetch:", Array(0))
End Sub

Private Sub Page1_Resize(Width As Int, Height As Int)
    
End Sub

Private Sub Application_Background
    Log("sono in background")
End Sub

Private Sub Application_Foreground
    App.ApplicationIconBadgeNumber=0
End Sub

Sub Application_ReceiveLocalNotification (ln As Notification)
    'this event will fire if the scheduled notification happend when the app was running
    hd.ToastMessageShow("NA: " & ln.AlertBody, True)
End Sub

After few minute i have this message in Log:

Can't endBackgroundTask: no background task exists with identifier 403, or it may have already been ended. Break in UIApplicationEndBackgroundTaskError() to debug.

Any solution ?
Thank you
Marco
 

MarcoRome

Expert
Licensed User
Longtime User
After 10 minutes instead of seeing the notification i receive this message and nothing happens ( in debug ).
if i compile in release mode and i have the application in the background nothing happens.
What's wrong with the code reported ?
 

MarcoRome

Expert
Licensed User
Longtime User
You must test it in release mode.

FetchDownload should eventually be called. However there is no guarantee when will it happen and in which frequency.

Yes @Erel i understood everything and i followed your instructions step by step.
1. Download the attached zip file and copy main.m to <project>\Files\Special.
2. Compileted in Release Mode
3. Restart also device ( iphone 6s with 11.4 )
4. Run App and app is in the background.
5. The device is every open ( Leave the phone connected to the charger. )

But in 1 hours nothing happen i dont see any notification.
Here in attachment the project with test. Can you try ?
Thank you very much
Marco

N.B. The app is configured correctly and is seen as an app in the background

1.jpg


2.jpg


3.jpg
 

Attachments

  • BackGroundFetch.zip
    4.4 KB · Views: 424
Last edited:
Top