Notifications! How can I send data with my notifications and receive it in Lua within my Corona App?

Can you post your code? 

Got it to work. The docs have bits and pieces here and there. The Corona community could benefit from a step-by-step tutorial on how to use all of this. But a big shout-out and thanks to you, Rob, for sticking with this issue until it was resolved.

Hi Rob,

We still have one outstanding issue about how to receive notifications. Of course, there are three conditions in which a notification should be detected.

  1. The App is running and a notification is received.

SOLUTION: Custom data is passed from iOS through to Lua’s notification ‘custom’ property in JSON format.

  1. When the App is NOT running, but a user CLICKS on a notification and the App launches.
    SOLUTION: The Custom property is also set, but through different code entirely - into LaunchArgs.notifications.custom by simply putting “LaunchArgs = …” in our main.lua file.

  2. However, if the App is NOT running, and the user DOES NOT CLICK on a notification, and instead they independently open the App:
    PROBLEM - NO NOTIFICATION IS RECEIVED BY EITHER OF THESE METHODS. Am I missing something here? Or is this expected to be normal???

#3 this is the expected behavior. If you start the app by tapping on it’s icon from the home screen instead of interacting with the notification, your notifications will be lost. Your app will not receive them.  I’m not 100% sure that on Android, they will be cleared, but on iOS they will be cleared and not passed. This is true of every app on iOS.

Rob

Hi Rob,

What this tells me is that notifications cannot be used to send virtual items to a gamer - in other words, the OS (Android or iOS) could entirely bypass our App’s ability to get a sent notification and therefore, notifications are just that, notifications - they cannot be used to send any benefit or virtual item to a gamer. That must be handled by our game server. Thank you for your help on this. I would have gone down the wrong path using notifications as something more than a message.

But this problem is actually deeper.

Let’s suppose on Christmas, you want your gamers to get 100 Gold Bars. So, you send a notification. For those who never click on the notification, do you want them to miss out? Of course not. For this reason, the game code must communicate with it’s server to know which gamers are receiving their gold bars and what day it is - in this way, they get the Gold Bars whether they click on the notification or not.

However, let’s say that after they get their gold bars this way, they later click on the notification. The code must check with the game server to make sure the gamer had not yet received the gold bars or at least inform them that they have already received them.

This is a perfect example of how handling proper virtual items requires a game server and why notifications are completely unreliable for delivering them. Instead, they can be used to ‘notify’ the gamer. But in such cases, the developer will still need to see if they have already received the benefit mentioned in the notification.

That’s a long explanation, but hopefully it is clear enough for someone to understand and benefit from my discoveries here.

To implement notifications, you will need to setup your build.settings in accordance with the Corona API docs.

The following then assumes you have acquired a subscription to Push Woosh (www.pushwoosh.com). The basic is FREE, but at the time this forum post was written, we had a $49 per month for unlimited subscriptions for a certain number of apps.

To implement specifically with Push Woosh, here is what you do:

Step 1) In your main.lua file, put:

local launchArgs = ... --======================================================================================= -- Pushwoosh notifications functions --======================================================================================= native.setProperty( "applicationIconBadgeNumber", 0 ) -- clear number on icon pushwoosh = require("pushwoosh") pushwoosh.setup(launchArgs) --this will catch any notifications that may have been pressed by the user causing the App to launch

Step 2) Wherever in your code that your App user indicates that he/she will accept your notifications, or if you just want the system to ask him/her and set the OS flag accordingly, you will place this code:

pushwoosh.setup() -- this will only run once, assuming that you keep a boolean flag not to run this again once the user has already given you permission

Step 3) Save the following code to pushwoosh.lua:

--================================================================================================ -- pushwoosh.lua --================================================================================================ local pushwoosh = {} local pw\_app\_code = {} local TAG = "[Pushwoosh] " local function sendRequest( method, args, success, fail ) local PW\_URL = "https://cp.pushwoosh.com/json/1.3/" .. method local function networkListener( event ) if ( event.isError ) then if ( error ~= nil ) then error( event ) end print( TAG .. PW\_URL .. " request failed: " .. json.encode(event) ) else if ( success ~= nil ) then success( event ) end print ( TAG .. PW\_URL .. " Response: " .. json.encode(event.response) ) end end local jsonvar = {} jsonvar = json.encode(args) local post = jsonvar local headers = {} headers["Content-Type"] = "application/json" headers["Accept-Language"] = "en-US" local params = {} params.headers = headers params.body = post print( TAG .. "Sending request " .. jsonvar .. " to " .. PW\_URL ) network.request ( PW\_URL, "POST", networkListener, params ) end local function registerDevice( pushToken, app\_code ) local deviceType = 1 -- default to iOS if ( system.getInfo("platformName") == "Android" ) then deviceType = 3 end local commands\_json = { ["request"] = { ["application"] = app\_code, ["push\_token"] = pushToken, ["language"] = system.getPreference("ui", "language"), ["hwid"] = system.getInfo("deviceID"), ["timezone"] = 3600, -- offset in seconds ["device\_type"] = deviceType } } local function onSuccess( event ) local registrationEvent = { name="pushwoosh-registration-success" } Runtime:dispatchEvent( registrationEvent ) end local function onError( event ) local registrationEvent = { name="pushwoosh-registration-fail" } Runtime:dispatchEvent( registrationEvent ) end sendRequest( "registerDevice", commands\_json, onSuccess, onError) end local function sendAppOpen( app\_code ) local commands\_json = { ["request"] = { ["application"] = app\_code, ["hwid"] = system.getInfo("deviceID") } } sendRequest( "applicationOpen", commands\_json, nil, nil) end local function sendPushStat( app\_code, hash ) local commands\_json = { ["request"] = { ["application"] = app\_code, ["hwid"] = system.getInfo("deviceID"), ["hash"] = hash } } sendRequest( "pushStat", commands\_json, nil, nil) end local function sendDeliveryMessage( app\_code, hash ) local commands\_json = { ["request"] = { ["application"] = app\_code, ["hwid"] = system.getInfo("deviceID"), ["hash"] = hash } } sendRequest( "messageDeliveryEvent", commands\_json, nil, nil) end local function sendStat( event ) local hash = nil if ( system.getInfo("platformName") == "iPhone OS" ) then hash = event.custom.pw.p elseif ( system.getInfo("platformName") == "Android" ) then hash = event.androidGcmBundle.p end if ( hash ~= nil ) then -- We cannot track message delivery until user opens it -- But if it is opened it is definitely delivered sendDeliveryMessage ( pw\_app\_code, hash ) sendPushStat( pw\_app\_code, hash ) else print( TAG .. "Error! Missing hash in push payload" ) end end local function onNotification( event ) print(json.prettify(event)) print( TAG .. "onNotification: " .. json.encode(event) ) if event.type == "remoteRegistration" then registerDevice( event.token, pw\_app\_code ) elseif ( event.type == "remote" ) then -- filter out GCM service notification if ( event.androidGcmBundle ~= nil and event.androidGcmBundle.from == "google.com/iid" ) then print( TAG .. "Warning! GCM registration token may be invalid. Try reregister with GCM." ) else sendStat(event) local notificationEvent = { name="pushwoosh-notification", data=event } Runtime:dispatchEvent( notificationEvent ) end end end --================================================================================================ -- public methods -- --================================================================================================ function pushwoosh.registerForPushNotifications( app\_code, launchArgs ) pw\_app\_code = app\_code sendAppOpen( app\_code ) if launchArgs and launchArgs.notification then print( TAG .. "Application was launched from a cold start in response to push notification" ) onNotification( launchArgs.notification ) end Runtime:addEventListener( "notification", onNotification ) -- For iOS, the app must explicitly register for push notifications if ( system.getInfo("platformName") == "iPhone OS" ) then local notifications = require( "plugin.notifications" ) notifications.registerForPushNotifications() end end --================================================================================================ function pushwoosh.setup(launchArgs) --------------------------------------- -- On notification --------------------------------------- local function onNotification( event ) print(json.prettify(event)) native.showAlert( "Notification:", event.data.alert or "", { "OK" } ) -- reset badge number native.setProperty( "applicationIconBadgeNumber", 0 ) end --------------------------------------- -- On registration success/failed --------------------------------------- local function onRegistrationSuccess( event ) print( "Registered on Pushwoosh" ) end local function onRegistrationFail( event ) native.showAlert( "Notification Registration Failed", "An Error Contacting the Server has Occurred. Please try again later from the application settings.", {"OK"}) end if booleanFlag and booleanFlag==1 then Runtime:addEventListener( "pushwoosh-notification", onNotification ) Runtime:addEventListener( "pushwoosh-registration-success", onRegistrationSuccess ) Runtime:addEventListener( "pushwoosh-registration-fail", onRegistrationFail ) pushwoosh.registerForPushNotifications( "xxxxx-xxxxx", launchArgs ) end end --================================================================================================ return pushwoosh

Step 4) Make sure that the booleanFlag variable (whatever you called it) discussed in the ‘comment within the code’ in Step 2 above is properly set and referenced properly in pushwoosh.lua line 189 above:

if booleanFlag and booleanFlag==1 then

Step 5) Be sure to insert your pushwoosh ID into the line just 4 lines from the end of pushwoosh.lua line 193 above:

pushwoosh.registerForPushNotifications( "xxxxx-xxxxx", launchArgs )

That’s it! I hope it helps you.

You are exactly right. Push notifications were never designed to pass game play data, regardless of the time (your gold bars). I wish it wasn’t this way, but it’s how Apple and Google implemented this. It’s your responsibility to have your app talk to your online service to manage actually communications. I understand why Apple and Google did it, but for inter-game communications you do have to check with your server. Almost think of the notification as an alert telling you to check with your server and that interacting with a notification is a convenient way to start your app for you (instead of the user having to find the icon).

Rob