iOS Question Trying to get silent push notifications working

henrywood

Active Member
Licensed User
I am trying to grasp push notifications on iOS and also trying to get silent notifications working.

Silent notifications should be supported on iOS7+ according to http://hayageek.com/ios-silent-push-notifications/

I have this code:

B4X:
'Code module
#Region  Project Attributes
   #ApplicationLabel: B4i Example
   #Version: 1.0.0
   'Orientation possible values: Portrait, LandscapeLeft, LandscapeRight and PortraitUpsideDown
   ' FIXME
   #iPhoneOrientations: Portrait, LandscapeLeft, LandscapeRight
   #iPadOrientations: Portrait, LandscapeLeft, LandscapeRight, PortraitUpsideDown

   ' Register for *SILENT* push notifications
   #PlistExtra: <key>UIBackgroundModes</key><array><string>remote-notification</string></array>

   ' DEFAULT APP FONT
   #AppFont: roboto-light.ttf

#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 Page As Page

   Dim theURI As String

   Dim Const POSITION_TOP_LEFT As Int  = 1
   Dim Const POSITION_TOP_RIGHT As Int = 2
   Dim Const POSITION_BOTTOM_LEFT As Int = 3
   Dim Const POSITION_BOTTOM_RIGHT As Int = 4
   Dim Const POSITION_CENTER As Int = 5

   Public Const ADS_GRACE_PERIOD_DAYS As Int = 7           '   7 Days grace period for ads

   ' Valid anims:    zoom_enter, zoom_exit
   '         card_flip_left_in, card_flip_left_out
   '         card_flip_right_in, card_flip_right_out
   '         fade_out, fade_in
   Public ACTIVITY_ANIMATION_IN_DEFAULT As String = "zoom_enter"   '   Default inAnimation
   Public ACTIVITY_ANIMATION_OUT_DEFAULT As String = "zoom_exit"   '   Default OutAnimation

   ' Get from Google Console
   Dim GCM_API_KEY As String = "XXXXX"

   #If B4A
     Dim locale As AHLocale : locale.Initialize
     Dim trans As AHTranslator : trans.Initialize(File.DirAssets, locale.ISOCode)
     Dim dt As AHDateTime : dt.Initialize
   #End if

   Public CURRENTUSER As User
   Public CurrentNumberOfBeaconsToday As Int = 0

   ' Global ACTIVITY DESIGN
   Public Const DEFAULT_FONT As String = "roboto-light.ttf"
   Public Const DEFAULT_HEADLINE_SIZE As Int = 20
   Public Const FULLSCREEN_ON_GLOBALLY As Boolean = True
   Public Const ACTIVITY_GLOBAL_BG_COLOR As Int = Colors.ARGB(255, 255, 255, 255)
   Public Const ACTIVITY_GLOBAL_TXT_COLOR As Int = Colors.ARGB(0, 0, 0,0 )

   Public STARTED_FROM_HOME_PAGE_SHORTCUT As Boolean = False

   Public Const TOPMENU_MAX_NUMBER_OF_VISIBLE_ITEMS_AT_A_TIME As Int = 8
   Public Const DIALOGS_ANIMATION_DEFAULT As String = "zoom"     '   Default animation to use when showing dialogs
                                   '   Available animations:
                                   '   zoom
                                   '   slide_from_top, slide_from_top_and_back
                                   '   slide_from_bottom, slide_from_bottom_and_back,
                                   '   slide_from_left,slide_from_left_and_back,
                                   '   slide_from_right,slide_from_right_and_back
   Dim GPS1 As Location
   Dim DB As SQL

   'This code is essential if you want to use the menu for most activity.
   Dim MenuItem As List

   ' TODO: Add support for only showing X (configurable at signup) ads from the same company within a 24 hour
   '     window...


   Dim TRACKING_SIMILARITY_PCT As Double = 80.00

   ' TIMERS
   Dim Clear24Timer As Timer
   Dim CLEAR_SEEN_ADS_24_INTERVAL As Int = 864000000 : Clear24Timer.Initialize("Clear24Timer", CLEAR_SEEN_ADS_24_INTERVAL) : Clear24Timer.Enabled = True' Every 24 hours
   Dim AdsSeenTimer As Timer : AdsSeenTimer.Initialize("AdsSeenTimer", ADS_GRACE_PERIOD_DAYS * 86400) : AdsSeenTimer.Enabled = True

   Dim DEVICE_ID As String

   Dim PROXIMITY_THRESHOLD_NEAR As Int = 5
   Dim PROXIMITY_THRESHOLD_MIDDLE As Int = 15
   Dim PROXIMITY_THRESHOLD_FAR As Int = 400
   #If DEBUG
   Dim APP_VENDOR_ID As String = "F782DA6-4FA2-4E98-8024-BC5B71E0893E"
   Dim APP_APPLICATION_NAME As String = ":%s" ' This string *MUST* match the ProximityUUID of the ANDROID APP !!!
   #End If
   #If RELEASE
   Dim APP_VENDOR_ID As String = "FE1D7269-84E6-4E54-BD95-8447D088ED6F"
   Dim APP_APPLICATION_NAME As String = "xxxx:%s" ' This string *MUST* match the ProximityUUID of the iOS APP !!!
   #End If

   #IF DEBUG
   Public Const DEBUG As Boolean = True
   #End If
   #If RELEASE
   Public Const DEBUG As Boolean = False
   #End If
   #If RELEASE_INTERNAL
   Public Const DEBUG As Boolean =  True
   #End If

   ' MAPS AND LISTS
   Public AdsSeen As Map : AdsSeen.Initialize
   Public knownBeacons As Map : knownBeacons.Initialize

   Dim DB_FILENAME As String = "db.db"
 

End Sub

Private Sub Application_Start (Nav As NavigationController)

   NavControl = Nav

   ' Register for push notifications
   App.RegisterUserNotifications(True, True, True) 'allow badge, sound and alert
   App.RegisterForRemoteNotifications
   CheckForPushMessage

   ' Go to First page
   FirstPage.Show

End Sub

#Region PUSH NOTIFICATIONS

Private Sub CheckForPushMessage

   If App.LaunchOptions.IsInitialized AND _
     App.LaunchOptions.ContainsKey("UIApplicationLaunchOptionsRemoteNotificationKey") Then
     Dim data As Object = app.LaunchOptions.Get("UIApplicationLaunchOptionsRemoteNotificationKey")
     Dim no As NativeObject = app
     no.GetField("delegate").RunMethod("application:didReceiveRemoteNotification:", _
                       Array(App, data))
     End If

End Sub

' TODO: Is this sub called *ONLY* when the device is first registered for PUSH NOTIFICATIONS ???
Private Sub Application_PushToken (Success As Boolean, Token() As Byte)

     If Success Then
   
     Dim bc As ByteConverter
     Dim j As HttpJob
     j.Initialize("j", Me)
     'Dim paramsStr As String = "deviceID="&Main.DEVICE_ID&"&uuid="&Main.CURRENTUSER.ID&"&apptype=IOS&app="&Main.APP_APPLICATION_NAME.Replace("%s", "")
     Dim paramsStr As String = "deviceID=" & bc.HexFromBytes(Token) & "&uuid="&CURRENTUSER.ID&"&apptype=IOS&app="&APP_APPLICATION_NAME.Replace("%s", "")
     j.PostString(Callbacks.CB_DEVICE_REGISTRATION_URL & paramsStr)
     Else
     Utils.Log_("Error getting token: " & LastException)
     End If

End Sub

' Called if the app is not in the foreground
Private Sub Application_RemoteNotification (Message As Map)

     If DEBUG Then
     Utils.Log_("Remote notification: " & Message)
     End If

   Dim m As Map = Message.Get("aps")
     Dim tempMap As Map = Message.Get("data")
   Dim thetype As String = tempMap.Get("type")

   ' Parse the Data
   Dim Map1 As Map
   Dim List1 As List
   Map1.Initialize
   List1.Initialize

   Dim TYPE_OF_NOTIFICATION As Int = thetype

   If m.Get("content-available") = "1" Then       '   It's a silent notification

       ' Select what to do
     Select TYPE_OF_NOTIFICATION

       Case PushIncomingHandler.NOTIFICATION_TYPE_BEACONS_FOUND_CLEAR
         knownBeacons.Clear
   
       Case PushIncomingHandler.NOTIFICATION_TYPE_COMPANY_BOUGHT_MEMBERSHIP_ADDON

         Map1 = tempMap.Get("data")
         PushIncomingHandler.MarkThatCompanyHasMembership(Map1)
   
       Case PushIncomingHandler.NOTIFICATION_TYPE_COMPANY_CANCELLED_MEMBERSHIP_ADDON
         Map1 = tempMap.Get("data")
         PushIncomingHandler.RemoveThatCompanyHasMembership(Map1)
   
       Case PushIncomingHandler.NOTIFICATION_TYPE_DELETED_CATEGORIES
         List1 = tempMap.Get("data")
         PushIncomingHandler.DeleteCategories(List1)
   
       Case PushIncomingHandler.NOTIFICATION_TYPE_DELETED_TAGS
         List1 = tempMap.Get("data")
         PushIncomingHandler.DeleteTags(List1)

       Case PushIncomingHandler.NOTIFICATION_TYPE_DO_APPLICATION_UPDATE
           Map1 = tempMap.Get("data")
           Dim v As String = Map1.Get("version")
           CallSubDelayed2(Updater, "AskUpdate", v)
       
       Case PushIncomingHandler.NOTIFICATION_TYPE_EDITED_COMPANY
         Map1 = tempMap.Get("data")
         PushIncomingHandler.updateCompanyNaming(Map1)

       Case PushIncomingHandler.NOTIFICATION_TYPE_NEW_CATEGORY_ADDED
         Map1 = tempMap.Get("data")
         PushIncomingHandler.addNewCategory(Map1)
   
       Case PushIncomingHandler.NOTIFICATION_TYPE_NEW_COMPANY
         Map1 = tempMap("data")
         PushIncomingHandler.addNewCompany(Map1)

       Case PushIncomingHandler.NOTIFICATION_TYPE_NEW_SERVERS_INDEX
         PushIncomingHandler.reloadServersIndex

       Case PushIncomingHandler.NOTIFICATION_TYPE_NEW_TAGS_ADDED
         List1 = tempMap.Get("data")
         PushIncomingHandler.addNewTags(List1) 

       Case PushIncomingHandler.NOTIFICATION_TYPE_PUSHED_AD_FROM_COMPANY
         Map1 = tempMap.Get("data")
         CallSubDelayed2(AdViewer, "onAdFromCompanyArrival", Map1)

       Case PushIncomingHandler.NOTIFICATION_TYPE_RELOAD_CATEGORY_TREE
         PushIncomingHandler.reloadCategoriesTree

       Case PushIncomingHandler.NOTIFICATION_TYPE_DELETED_COMPANIES
         List1 = tempMap.Get("data")
         PushIncomingHandler.DeleteCompanies(List1)
   
       Case PushIncomingHandler.NOTIFICATION_TYPE_RELOAD_TAGS_INDEX
         PushIncomingHandler.reloadTagsIndex

       Case PushIncomingHandler.NOTIFICATION_TYPE_EDITED_LOCATION
         Map1 = tempMap.Get("data")
         PushIncomingHandler.updateLocationInfo(Map1)
     
       Case PushIncomingHandler.NOTIFICATION_TYPE_NEW_LOCATIONS_ADDED
         List1 = tempMap.Get("data")
         PushIncomingHandler.AddNewLocations(List1)
     
       Case PushIncomingHandler.NOTIFICATION_TYPE_DELETED_LOCATIONS
         List1 = tempMap.Get("data")
         PushIncomingHandler.DeleteLocations(List1)

       Case PushIncomingHandler.NOTIFICATION_TYPE_DELETED_ADS
         List1 = tempMap.Get("data")
         PushIncomingHandler.removeAdIDs(List1)
     
       Case PushIncomingHandler.NOTIFICATION_TYPE_EDITED_AD
         Map1 = tempMap.Get("data")
         PushIncomingHandler.updateAd(Map1)
     
       Case PushIncomingHandler.NOTIFICATION_TYPE_NEW_AD_ADDED
         Map1 = tempMap.Get("data")
         PushIncomingHandler.AddNewAd(Map1)
   
       ' When a user removes a friend from his friend list -> a notification of type
       ' "NOTIFICATION_TYPE_UNFRIEND_CURRENT_USER_FROM_REMOTE_USER" is sent to the device of
       ' the removed user. The message should carry info on what list the recipient should
       ' be removed from
       Case PushIncomingHandler.NOTIFICATION_TYPE_UNFRIEND_CURRENT_USER_FROM_REMOTE_USER
         Map1 = tempMap.Get("data")
         PushIncomingHandler.UnfriendCurrentUserFrom(Map1)

       ' When a user adds a friend from his friend list -> a notification of type
       ' "NOTIFICATION_TYPE_UNFRIEND_CURRENT_USER_FROM_REMOTE_USER" is sent to the device of
       ' the removed user. The message should carry info on what list the recipient should
       ' be added from
       Case PushIncomingHandler.NOTIFICATION_TYPE_BEFRIEND_CURRENT_USER_WITH_REMOTE_USER
         Map1 = tempMap.Get("data")
         PushIncomingHandler.BefriendCurrentUserWith(Map1)
   
       Case PushIncomingHandler.NOTIFICATION_TYPE_ADD_TO_A_SHARED_LIST
         Map1 = tempMap.Get("data")
         PushIncomingHandler.receiveMessageForShoppingList(Map1)

       Case PushIncomingHandler.NOTIFICATION_TYPE_REMOVE_FROM_A_SHARED_LIST
         Map1 = tempMap.Get("data")
         PushIncomingHandler.removeItemsFromUserFromShoppingList(Map1)

       Case Else
         If DEBUG Then
           Utils.Log_("Unknown type of push notification received: "& TYPE_OF_NOTIFICATION)
         End If
     
     End Select

     If DEBUG Then
       Utils.Log_("Received silent push notification: " & m)
     End If
 
     ' TODO: What do I need to call here for IOS to be happy ?

     Else                         '   Not a silent notification

       If DEBUG Then
       Utils.Log_("Received a normal push notification: " & m)
       End If
 
     End If

End Sub

Private Sub JobDone(j As HttpJob)

   If j.Success Then
     If DEBUG Then
       Utils.Log_("Token uploaded successfully.")
     End If
     Else
     If DEBUG Then
       Utils.Log_("Error uploading token")
     End If
     End If

     j.Release

End Sub

#End Region

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

End Sub

Private Sub Application_Background

End Sub

My questions:

1. Is the "Application_PushToken" sub called *ONLY* when the device is first registered for PUSH NOTIFICATIONS (like the registration in GCM) - and is the event fired only once and only after calling
App.RegisterUserNotifications(True, True, True) and
App.RegisterForRemoteNotifications
?

2. At the line that has the comment "TODO: What do I need to call here for IOS to be happy ?":
What do I need to call for iOS to be happy ? What confuses me is what I've read here:
http://www.g8production.com/post/72656082173/ios7-multitasking-silent-notifications about
returning a UIBackgroundFetchResult ?

All my processing of push notifications should be completed within the 30 seconds of wall clock time given by Apple. It simply updates the local DB with the data in the push message

3. In the case where the user has not allowed push notifications, will the silent push notifications that I try to get working also be affected ? And if so, what is the alternative to using push notifications ?

4. How can I find out if the user disallows or allows push notifications ? Can I react to some kind of event or can I read the settings ?

5. Will "Application_RemoteNotification" sub be called regardless of wether or not my application is running/is in the foreground ?

6. Is this line:
#PlistExtra: <key>UIBackgroundModes</key><array><string>remote-notification</string></array>

enough to support silent push notifications ?


Sorry for a long post but I hope that the subject is of interest to others as well who are (like me) starting out on the journey of iOS development....


Thanks


/Henrik
 
Last edited:

henrywood

Active Member
Licensed User
Currently it is not possible to intercept silent notifications as the app delegate doesn't implement the required method: application:didReceiveRemoteNotification:fetchCompletionHandler:
Since it is very important for me to have support for silent notifications (in order to finish the iOS version of my app), what are the chances that the next update to/version of B4i will support this method ?

If needed I would be willing pay for this change (as otherwise I cannot finish my app)
 
Top