iOS Tutorial Silent Push Notifications

Discussion in 'iOS Tutorials' started by Erel, Jul 9, 2015.

  1. Erel

    Erel Administrator Staff Member Licensed User

    This tutorial explains how you can use push notifications that don't show any visual cue to the user and start your app in the background for a limited time (up to 30 seconds).
    You can use it for example to download new content.

    Make sure to start with standard push notifications: https://www.b4x.com/android/forum/t...ions-push-messages-server-not-required.68645/

    1. Add the remote notification background mode:
    Code:
    #PlistExtra: <key>UIBackgroundModes</key><array><string>remote-notification</string></array>
    2. When a remote notification arrives the Application_RemoteNotification event will be raised. You have up to 30 seconds to do whatever your app needs to and then call CompletionHandler.Complete.

    3. Sending code: remove the notification element and add the content_available field:
    Code:
    If Topic.StartsWith("ios_"Then
       
    Dim iosalert As Map =  CreateMap("title": Title, "body": Body, "sound""default")
       
    'm.Put("notification", iosalert) 'comment this line
       m.Put("priority"10)
       m.Put(
    "content_available"True'<--- add
    End If
    Note that you can add other fields to 'data' map.

    Testing

    iOS will not start the app automatically if the user has killed it. This makes it a bit difficult to test that it really works.
    In order to test it you need to compile it in Release mode and run it once.
    Now install the app again and do not start it. Send a silent push message and the process should start.
    The app will not be visible. You can show a local notification to see that it is working.
    You can also use this tool to monitor the logs in release mode: iReleaseLogger - Read the logs in release mode
     
    Last edited: Oct 9, 2016
    fbritop likes this.
  2. mauro vicamini

    mauro vicamini Active Member Licensed User

    Is it possible to add other fields also to normal notifications (not silent)? If yes, there is a limt of size?
     
  3. Erel

    Erel Administrator Staff Member Licensed User

    Note that you should have started a new thread for this question.

    Yes, you can add custom fields to all notifications. The size limit depends on the device version: iOS 7 is 256 bytes and iOS8+ 2048 bytes.
     
  4. mauro vicamini

    mauro vicamini Active Member Licensed User

  5. fbritop

    fbritop Active Member Licensed User

    Anyone know why notifications in background do not work when we use:

    Code:
    #PlistExtra:<key>UIBackgroundModes</key><array><string>remote-notification</string></array>
    #PlistExtra:<key>UIBackgroundModes</key><array><string>bluetooth-central</string></array>
    #PlistExtra:<key>UIBackgroundModes</key><array><string>location</string></array>
    If I comment the second and third PlistExtra it works.
     
  6. fbritop

    fbritop Active Member Licensed User

    To whom it may help. same "keys" shoud go on the array.

    So:
    Code:
    #PlistExtra:<key>UIBackgroundModes</key><array><string>remote-notification</string></array>
    #PlistExtra:<key>UIBackgroundModes</key><array><string>bluetooth-central</string></array>
    #PlistExtra:<key>UIBackgroundModes</key><array><string>location</string></array>
    Should be:

    Code:
    #PlistExtra:<key>UIBackgroundModes</key><array><string>remote-notification</string><string>bluetooth-central</string><string>location</string></array>
     
  7. moster67

    moster67 Well-Known Member Licensed User

    I have been experimenting with silent push notifications and sometimes they work, other times my test-app is not launched (can not see my logs with B4iLogger). I noted that if I previously had "killed" my app, then it would not work. I found this from Apple's docs which seems to confirm my finding:

    I don't know about you, but during the day when I am using my iPhone, quite often do I kill various apps. In addition, I rarely switch off my device so it can be restarted. So for me, this behavior would be a problem...

    Testing 'normal push notifications', everything seems to work just fine without this problem.

    Let's say that I need to launch my app on my users' devices every 30 minutes so they can download some data, what other method/work-around could be implemented to overcome the shortcoming mentioned above and ensure regular communication between my server and the app? Could the 'Background fetch' feature somehow 're-trigger' the app (after a user-kill) and make silent push notifications start working again?
     
    Last edited: Nov 14, 2015
  8. Erel

    Erel Administrator Staff Member Licensed User

    moster67 likes this.
  9. moster67

    moster67 Well-Known Member Licensed User

    Thanks Erel. It seems like in this case I must indeed implement something on the server-side as suggested in the SO-thread and ask the user to open the App again with a non-silent push notification.

    In this regard, in your above tutorial for silent push notifications, you said to remove 'CheckForPushMessage' in Application_Start. If I now in my code must also enable normal push notifications, should I call it again? What I am asking is actually if my app can handle both normal push notifications and silent push notifications and if I must handle/write my code in a particular way to make sure that both will work at the same time. Any suggestions?
     
    Last edited: Nov 15, 2015
  10. Erel

    Erel Administrator Staff Member Licensed User

    There shouldn't be a problem with combining both types of notifications. You don't need the CheckForPushMessage sub.
     
  11. moster67

    moster67 Well-Known Member Licensed User

    I am still having some problems. I am still only testing silent push notifications and I would have expected to see a log B4iLogger when sending a silent push notification AFTER the device has been restarted.

    Can someone else please check if silent push notifications are being received after your have restarted your iOS device? According to documentation it should work. Thanks.
     
  12. moster67

    moster67 Well-Known Member Licensed User

    Started testing Silent Push Notifications again, after a pause, but this time it is not working at all. Really weird.

    I had a look at the EDIT (the link you added) and followed your updated instructions. Deleted the main.m file in the Special folder and downloaded the main.m file in the first post and put it in my b4i project folder (c:\Anywhere Software\B4i\Project). Modified my server as you wrote in the first post and so forth...

    I am testing this on my device, and not on the simulator. I have built the app in release mode using both my local MAC and the hosted compiler but no luck.

    The Application_RemoteNotification sub/event is not triggering - I checked this using a local notification (as in your example) but also by monitoring the logs using iReleaseLogger.

    I am wondering why you commented the following line in your example-code?
    Code:
    '#ProvisionFile: Push.mobileprovision
    If I comment this line in my code, I get an error.

    Of course, maybe the Apple-servers could be down but I have been trying this at different times during the day so I don't think so since Apple would surely ensure their servers would be up and running in a short time. Just to be sure I made a telnet connection from my server:
    Code:
    telnet gateway.sandbox.push.apple.com 2195
    and it connected fine....

    I am really getting lost here. Maybe the changes Apple did to Xcode 7 when it builds the project have broken something? Is it working for others?
     
    Last edited: Jan 3, 2016
  13. Erel

    Erel Administrator Staff Member Licensed User

    Does it work for you if you send a regular push message?
     
    Last edited: Jan 4, 2016
  14. moster67

    moster67 Well-Known Member Licensed User

    I got it sorted. I had updated my provision file but I was still using the older keystore on my server:mad:
    With iOS, there are many things to consider - much more than Android. Oh well, I guess by trial and error one will eventually learn!
     
    Erel likes this.
  15. marcick

    marcick Well-Known Member Licensed User

    I'm trying to play a sound after receiving a silent push notification, but it doesn't work

    Code:
    Main.MyPlayer1.Initialize(File.DirAssets, fn & ".wav","MyPlayEnd")
        Main.MyPlayer1.Looping=
    false
        Main.MyPlayer1.Play
    I can see the log, I can show a local notification, but no sound. The sound i splyed only if receiving the notification while the app is active

    Is there any limitation in the kind of code that can be executed after triggering the notification event ?
     
  16. Erel

    Erel Administrator Staff Member Licensed User

  17. marcick

    marcick Well-Known Member Licensed User

    This is the code, tested in RELEASE on a Iphone6S

    Code:
    Private Sub Application_RemoteNotification (Message As Map)
           
    Log("Remote notification")
           
    Dim m As Map = Message.Get("aps")
           
    Log(m.Get("alert"))
        
    Dim ln As Notification
           ln.Initialize(
    DateTime.Now + 1 * DateTime.TicksPerSecond)
           ln.AlertBody = 
    "This is a local notification"
           ln.Register
        MyPlayer1.Initialize(
    File.DirAssets, "bubo3.wav","MyPlayEnd")
        MyPlayer1.Looping=
    False
        MyPlayer1.Play       
    End Sub
    Sub MyPlayEnd_Complete
        
    Dim no As NativeObject = App
        no = no.GetField(
    "delegate")
        no.RunMethod(
    "complete:"Array(0))
    End Sub
    When I send a SILENT PUSH NOTIFICATION I have two behaviour:

    1) App Foreground: Event fired, I have the log, I have the local notification, I hear the sound "bubo3"
    2) App background: Event fired, I have the log, I have the local notification, but no sound "bubo3"

    In the second case, I see this also in the log with grey color:

    didReceiveRemoteNotification fetchCompletionHandler
    Warning: Application delegate received call to -application:didReceiveRemoteNotification:fetchCompletionHandler: but the completion handler was never called.
    Application_Remotenotification

    Besides this Mplayer problem, I have tried to add other code to the event above (a RDC connection that uses a background task for example) that seems not to work properly.
     
  18. Erel

    Erel Administrator Staff Member Licensed User

    Have you set the audio session?
     
  19. marcick

    marcick Well-Known Member Licensed User

    Yes.
    I'll try again from scratch and be back
    Thanks
     
  20. netkomm

    netkomm Active Member Licensed User

    Hi Erel,

    this example works - however there is one condition where it does not.
    I am building an app to log all the notifications received:

    - when the app is open then a local notification is triggered and the notification logged (and it's ok);
    - when the app is in background mode the notification is triggered and IF I click the notification then the notification data is passed to the app. (and it's ok)

    However IF I receive a notification when the app is in background mode and I open directly the app instead, there is no notification data sent to the app UNTIL I go and click on the notification in the notification centre.

    I do understand that I should be able to "execute" a background job (up to 30 sec. max) but it does not seem to work like that.

    I used the source provided and placed the main.m file in the "Special" folder.

    Code:
    Private Sub Application_RemoteNotification (Message As Map)
       
    Log("Remote notification: " & Message)
       
    Dim m As Map = Message.Get("aps")
       
    Log(m)
       
    Log(m.Get("alert"))
       
    Msgbox("remote: " & Message, "")
       
    Dim ln As Notification
       ln.Initialize(
    DateTime.Now + 2 * DateTime.TicksPerSecond)
       ln.AlertBody = 
    "This is a local notification"
       ln.Register
       
    Log ("message received")
       
    Dim no As NativeObject = App
       no = no.GetField(
    "delegate")
       no.RunMethod(
    "complete:"Array(0))
    End Sub
     
Loading...