iOS Tutorial Push notifications

B4i v1.50 added support for push notifications. Push notifications feature requires some configuration.
Patience is a virtue ;)

The following steps are required inside Apple developer console:
1. Create a new explicit (non-wildcard) App ID with the package name of the push app. For example anywheresoftware.b4i.push. Enable push notification service.
2. Create an Apple Push Notification SSL certificate. Use the same certSigningRequest.csr file that you previously created.
3. Create a provision file with the new App ID.

Note that you can always delete all certificates and provisions and start from scratch.

The last step is done in the IDE by clicking on Tools - Build Server - Create Push Keystore. This sends the required files to the Mac builder which then creates a file named push.keystore. This file will be used by the B4X Push Server to connect to Apple service.

Make sure to switch to HD by clicking on the small gear button:


At the end of the process the key folder should look like:

SS-2014-12-24_11.45.12.png


Code

Whenever the app starts we need to register the app for remote notifications. This is done with this code:
B4X:
App.RegisterUserNotifications(True, True, True) 'allow badge, sound and alert
App.RegisterForRemoteNotifications

The PushToken event will be raised with the device token. We then send the token to the push server:
B4X:
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)
     j.PostString(ServerUrl & "/devicetoken", "token=" & bc.HexFromBytes(Token) & "&type=1")
   Else
     Log("Error getting token: " & LastException)
   End If
End Sub

Private Sub JobDone(j As HttpJob)
   If j.Success Then
     Log("Token uploaded successfully.")
   Else
     Log("Error uploading token")
   End If
   j.Release
End Sub

The Application_RemoteNotification event will be raised when a message arrives while the app is in the foreground. If the app is not in the foreground then a standard alert message will appear. The user can click on the message to start the app.
The Application_RemoteNotification event will be fired after the app has started.

B4X:
Private Sub Application_RemoteNotification (Message As Map, CompletionHandler As CompletionHandler)
   Log("Remote notification: " & Message)
   Dim m As Map = Message.Get("aps")
   Log(m)
   Log(m.Get("alert"))
   CompletionHandler.Complete
End Sub

Note the new signature of Application_RemoteNotification. You should call CompletionHandler.Complete once you are done with the task related to the message. This is mainly important for silent push messages, though you should always call it.

You should use the #ProvisionFile attribute to explicitly select the push.mobileprovision file.

See also:
Apple documentation: https://developer.apple.com/library...icationsPG/Chapters/CommunicatingWIthAPS.html
B4X Push Server: https://www.b4x.com/android/forum/threads/b4x-push-server.48560/
Managing multiple certificates / provision files
 
Last edited:

imbault

Well-Known Member
Licensed User
I would like when such a app is running and is on Foreground, the push message have to same behaviour than if the app is in background. Is that possible ?

Because I'm doing an application (let's say like Yo), where the user can send push notications, but also receive when he is on the App, but Notifications must be the same, not depending of the state of the app, Fore and Back ground.

Question 2, it that possible to get access to the "Special folder" from an app, if yes, is that a File.??? something?

Thanks

@Erel say in post #1
The Application_RemoteNotification event will be raised when a message arrives while the app is in the foreground. If the app is not in the foreground then a standard alert message will appear
 
Last edited:

Erel

Administrator
Staff member
Licensed User

imbault

Well-Known Member
Licensed User
Please start a new thread for this question.

See the last two code snippets in the first post: https://www.b4x.com/android/forum/threads/push-notifications.48562/
Application_RemoteNotification will be raised on both cases.

I'm Sorry @Erel , this doesn't work when the application is running, I received no push, neither from the button click neither from a call from my PC
http://192.168.0.13:51044/send?password=123&text=time to go&badge=1&sound=claque.mp3

But, if the app is not in foreground, it works perfectly.

This code is the same as post #1 + send capabilities.

Anyway, the sample push from post #1 + code snippet does not work when the app is foreground

B4X:
'Code module
#Region  Project Attributes
    #ApplicationLabel: B4i Example
    #Version: 1.0.0
    'Orientation possible values: Portrait, LandscapeLeft, LandscapeRight and PortraitUpsideDown
    #iPhoneOrientations: Portrait, LandscapeLeft, LandscapeRight
    #iPadOrientations: Portrait, LandscapeLeft, LandscapeRight, PortraitUpsideDown
    #ProvisionFile: Push.mobileprovision
#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
    Private Const ServerUrl As String = "http://192.168.0.13:51044"
End Sub

Private Sub Application_Start (Nav As NavigationController)
    NavControl = Nav
    Page1.Initialize("Page1")
    Page1.Title = "Page 1"
    Page1.RootPanel.Color = Colors.White
    Dim but As Button
    but.Initialize("but",but.STYLE_SYSTEM)
    but.Text ="SEND PUSH"
    Page1.RootPanel.AddView(but,100,100,100,20)
    NavControl.ShowPage(Page1)
    App.RegisterUserNotifications(True, True, True)
    App.RegisterForRemoteNotifications
    CheckForPushMessage
End Sub

Sub but_Click
       Dim job As HttpJob
    job.Initialize("jobsend", Me)
    job.PostString(ServerUrl & "/send", "password=123" & "&text=Hello" & "&badge=1" & "&sound=piece.mp3")
End Sub

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)
        j.PostString(ServerUrl & "/devicetoken", "token=" & bc.HexFromBytes(Token) & "&type=1")
    Else
        Log("Error getting token: " & LastException)
    End If
End Sub

Private Sub JobDone(j As HttpJob)
    Log(j.JobName)
    If j.Success Then
        Log("Token uploaded successfully.")
    Else
        Log("Error uploading token")
    End If
    j.Release
End Sub

Private Sub Application_RemoteNotification (Message As Map)

    Log("Remote notification: " & Message)
    Dim m As Map = Message.Get("aps")
    Log(m)
    Log(m.Get("alert"))
End Sub

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

Private Sub Application_Background
  
End Sub
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
 
Last edited:

imbault

Well-Known Member
Licensed User
Are you checking the logs? The push message box will not appear. However Application_RemoteNotification event will be raised.

Of course, it will raise, I saw it, however, the behavior of the notification is completely altered as a normal notification, that's the problem, so how to handle the same behavior of a notification, if the app is running on foreground.
 

imbault

Well-Known Member
Licensed User
Lol, I've got that and it was what I supposed, so I handle the notification event when it raises in the app.
Thank you Erel
 

fbritop

Active Member
Licensed User
We have 2 Apps developed by b4i right now, application A and B

I have started a second (B) application now. First one (A) already on appStore.

My second App, generated the 3 initial files:
b4i.keystore
b4i.p12
certSigningRequest.csr

I went to Apple's Certificates, Identifiers & Profiles.

-Generate a new App ID for B
-ios_development.cer is the same file as on application A, as I cannot have more than one developer
-Generated a new dev certificate for APNs Development iOS with the CSR generated by application B
-Generated a new iOS provisioning profile with the new App ID for B

So from the initial 3 files now we have
aps_development.cer
devLlavemovil.mobileprovision
ios_development.cer


When I try to compile it throws the following error:

Check dependencies
Code Sign error: No codesigning identities found: No codesigning identities (i.e. certificate and private key pairs) that match the provisioning profile specified in your build settings (“devLlavemovil”) were found.
CodeSign error: code signing is required for product type 'Application' in SDK 'iOS 8.4'

Do we have to unregsiter a developer that was created with CSR from A, when we try to create the certificates and provision for B, so that the developer is generated with a CSR from B?

Thanks
FBP
 

Gijsen

Member
Licensed User
What can be wrong when Application_RemoteNotification isn't called when a push message is sent ?
I've tested both with the Push Notification Tool and B4X Push Server.

The app gets a token assigned, and is able to post it to the push server and my own script.
 

Gijsen

Member
Licensed User
Yes, that sub does exist.

I think there is something wrong with the b4i.p12 file I'm using.
I've made a new thread for this with all the steps I took.
 

moster67

Expert
Licensed User
It seems like it possible to disable push notifications within ours apps.
See 2nd answer (with 22 votes) in this SO-thread.

In B4i we have 'app.registerForRemoteNotificationTypes" to enable.
Is it possible (using inline ObjC-code) to disable them using 'unregisterForRemoteNotificationTypes'? If yes, could someone please provide some code for it?

Thanks.
 

moster67

Expert
Licensed User
Thanks Erel. It seems to work after the 'small' tests I tried although I would need to test it more to see how it behaves in different scenarios.

An alternative way is to let the user modify the settings themselves. You can obtain this by using the following code (seems to work from iOS 8 and upwards)

B4X:
Dim NativeMe As NativeObject = Me
NativeMe.RunMethod("openNotificationSettings",Null)

#If OBJC
- (void)openNotificationSettings {
   if (&UIApplicationOpenSettingsURLString != NULL)
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}
#end if

This will open a screen where users can change all settings relative to your app.

Edit: oops. It seems like Erel already provided a method to obtain the settings relative to your app, namely:

B4X:
If Main.App.OSVersion >= 8 Then
    Main.app.OpenURL("app-settings:")
End If
 
Last edited:

moster67

Expert
Licensed User
Here is another ObjC code-snippet which may be useful if you want to check if notifications are enabled or not. Only available from iOS version 8 and upwards.

B4X:
If App.OSVersion >= 8 Then
    Dim NativeMe As NativeObject = Me
    Dim isRegged As Boolean
    isRegged=NativeMe.RunMethod("isRegisteredForRemoteNotifications", Null).AsBoolean
End If

#If OBJC
- (BOOL)isRegisteredForRemoteNotifications {
    if ([[UIApplication sharedApplication] isRegisteredForRemoteNotifications]) return YES;
    return NO;
}
#end if
 
Last edited:

tufanv

Expert
Licensed User
Hello,

1)Is b4x push server server have to run 24/7 or when just sending a notification?
2) I receive error uploading token error. The server ip and port is entered correctly
 
Last edited:

tufanv

Expert
Licensed User
I tested everything with development mode and works perfect. Now, besides changing the lines in config txt do i have to change the keystore password to my distrubition private sign key and create push.keystore again with distrubition keys and files ?
 
Top