Android Tutorial Simple Push Framework

It is recommended to use Firebase for new projects: FirebaseNotifications - Push messages / Firebase Cloud Messaging (FCM)

This solution allows you to use the standard GCM push framework without an online server.

SS-2013-12-12_15.48.10.png


You should first be familiar with GCM and get an API Key and Project id as explained here:
Android push notification (GCM) framework and tutorial

The desktop solution is based on this B4J project: Building a mini "Email based server"

When a user registers the device, an email is sent to the desktop tool. The desktop tool then adds the device to an internal store. If the desktop tool is not online then nothing bad happens. The mail will wait until it the tool is started.

The emails are only used for the registration process.

Note that you can send to multiple targets at once with this solution (unlike the other solution).
As it is written in B4J it should be simple to extend it as needed.

In order to use it you should set the ApiKey variable in the B4J project as well as the mailbox parameters.

You also need to set the mailbox parameters on the device (PushService) and set the SenderId in the Main module.

Tips / Notes

- The B4J project depends on jMsgboxes library (and other internal libraries). It also requires B4J v1.05+.
- If you plan to distribute your app on many devices then you should probably not use a free mail service such as Gmail for the devices. You can use the default email client instead. However in that case it is better to "obfuscate" the message before sending it as the user will see the mail content.
 

Attachments

  • PushDevice.zip
    8.6 KB · Views: 3,092
  • PushDesktop.zip
    6.3 KB · Views: 2,791
Last edited:

defillo

Member
Licensed User
Longtime User
nice work, Erel. works perfectly
easy to send pushes from the desktop but what about pushes from device "A" to device "B" ?
 

qsrtech

Active Member
Licensed User
Longtime User
Hi I'm running into issues with GCM. I need this code converted to b4a
B4X:
/**
* Gets the current registration ID for application on GCM service.
* <p>
* If result is empty, the app needs to register.
*
* @return registration ID, or empty string if there is no existing
*        registration ID.
*/
private String getRegistrationId(Context context) {
    final SharedPreferences prefs = getGCMPreferences(context);
    String registrationId = prefs.getString(PROPERTY_REG_ID, "");
    if (registrationId.isEmpty()) {
        Log.i(TAG, "Registration not found.");
        return "";
    }
    // Check if app was updated; if so, it must clear the registration ID
    // since the existing regID is not guaranteed to work with the new
    // app version.
    int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
    int currentVersion = getAppVersion(context);
    if (registeredVersion != currentVersion) {
        Log.i(TAG, "App version changed.");
        return "";
    }
    return registrationId;
}
...
/**
* @return Application's {@code SharedPreferences}.
*/
private SharedPreferences getGCMPreferences(Context context) {
    // This sample app persists the registration ID in shared preferences, but
    // how you store the regID in your app is up to you.
    return getSharedPreferences(DemoActivity.class.getSimpleName(),
            Context.MODE_PRIVATE);
}
 

qsrtech

Active Member
Licensed User
Longtime User
Hi, after further evaluation of the "code" I realized it just uses the "PreferenceManager". At first I thought there was a way to access the GCM framework to return the regid assigned to my app/projectid. I've ported it as needed to work for me. The issue I was having was that my regid's no longer worked all the time after the app was updated. This should resolve it. Thanks anyways.

For those interested here's the code I used:
B4X:
'global code module
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim PROPERTY_REG_ID As String= "registration_id"
    Dim PROPERTY_APP_VERSION As String= "appVersion"
    Dim AppVersion As String
End Sub

Sub getRegistrationID(SenderID As String) As Boolean
    Dim regid As String
    Dim pm As PreferenceManager
    regid=pm.GetString(SenderID)
    If regid="" OR AppVersion<>QSRGlobals.GetVersionname Then
        Log("getRegistrationID=false")
        Return False
    Else
        Log("getRegistrationID=true")
        Return True
    End If
End Sub

Sub storeRegistrationID(SenderID As String,regID As String)
    Dim pm As PreferenceManager
    pm.SetString(SenderID,regID)
End Sub

'in main activity i need to set the global appversion to the existing one stored cause I use several different GCM ProjectID's within one app so I can't update the appversion after any of them are registered cause it will affect any other potential registrations
    If FirstTime Then
        Dim pm As PreferenceManager
        Globals.AppVersion=pm.GetString(Globals.PROPERTY_APP_VERSION)
        'update with current version so next time app is started we get the last version used
        pm.SetString(Globals.PROPERTY_APP_VERSION,QSRGlobals.GetVersionname)
    End If

'this is called in an activity that needs to use the push service, i.e. Activity_Create
        If Globals.getRegistrationID(ProjectID)=False Then
            CallSubDelayed3(PushService, "RegisterDevice", False,ProjectID)
        End If

'call this in the pushservice's HandleRegistration
            Globals.storeRegistrationID(ProjectID,rid) 'note since I use multiple projectID's this global ProjectID is set in the pushservice's 
Sub RegisterDevice (Unregister As Boolean,pid As String)
        ProjectID=pid 'need this set globally cause the GCM framework doesn't return which projectid the regid that comes back is associated with

Hope that helps someone one day...
 
Last edited:

walterf25

Expert
Licensed User
Longtime User
Hi Thanks for this tutorial, i actually have a few questions, i can't seem to get this to work, i mean in runs fine, but when i click on the check now button, i don't see any devices, on the POP3 example, there's a string called API key where do I get that key from, i've added my gmail address along with my password, but i can't seem to get it to work, i've also installed the push program on my android device, and that works fine when i run it but i can't seem to understand the other part, can you please shed some light on this issue?

Thanks,
Walter
 

walterf25

Expert
Licensed User
Longtime User

Uitenhage

Member
Licensed User
Longtime User
Once you have the other device registration id then it should be simple to send messages. You can use the same code as in this example to send the messages.

Love this sample. Love having a B4J app to play with.

In addition to Server-to-Device and Device-to-Device messages can GCM be used for more than registration in a Device-to-Server scenario. I'm looking at replacing a Web Service 'polling' scheme with a push scheme where the Device has data to deliver (currently to a Web Service) as well as the Server having data for the Device. If this is possible I'd appreciate some sample code for D-to-D and D-to-S messages or links to relevant sites.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Thanks for the reply Erel, i'am actually registering my app first, but i still don't see the device name with the b4j example you're providing, am I missing something?
What happens when you run the Android app and register the device? Is the registration successful? Have you set the correct mail settings in the devive app?

@Uitenhage I'm not sure that I understand. How is the server polling the device?
 

walterf25

Expert
Licensed User
Longtime User
What happens when you run the Android app and register the device? Is the registration successful? Have you set the correct mail settings in the devive app?

@Uitenhage I'm not sure that I understand. How is the server polling the device?
Erel, yes the registration is succesful, i've added a log(RID) line to see the registration ID Number, so yes the registration is succesful. And yes i have set up my e-mail address and password correctly too, i'm not sure what else i could be doing wrong?
 

SueHale

Member
Licensed User
Longtime User
Hi Erel,

Wonder if you might be able to provide some assistance with what would be an issue.

Using two Android devices, works very well if I create two different user names. All registered via email and functions great. If use the same name on both devices can only send to one device, as in the other name is not shown (which would of course be the same in this instance)

This could be tested by using your first name entered exactly the same on two test devices.

Thank-you for the work put in on B4J and this interesting tutorial and any insight you can provide.

Sue.
 

deantangNYP

Active Member
Licensed User
Longtime User
Need your expertise.
I manage to setup the following:
Project ID: xxxx
Project Number: yyyy
Android API Key: zzzz or should I be generating server key for this desktop app?

Unfortunately, just could not register my device. I will receive "INVALID_SENDER" or "Error Sending Request" message when I select "Register". May I know what is wrong?
SenderId = Project ID or Project Number?
Thanks
 
Last edited:

deantangNYP

Active Member
Licensed User
Longtime User
I think I configured the SenderId correctly, SenderID = Project ID as shown in the attachment.
Both the PushDevice and PushDesktop need to run concurrent?
Thanks.

The error you get is not related to the server. Only to the client.

Seems like you didn't configure the SenderId value in the device app.
 

Attachments

  • simple.JPG
    simple.JPG
    23.4 KB · Views: 1,045
  • Capture2.JPG
    Capture2.JPG
    26.8 KB · Views: 997
Top