I have a test app to send push notifications between a couple of devices using Parse.com on iOS. What’s worrying is that I can’t send the custom data and I don’t know if it is Corona or Parse or my code which is wrong. The bug in Corona was fixed a year ago and Parse has (limited) instructions on how to do it, so maybe it’s me?
The test code is my modified version of the Parse API from the Code Exchange (to provide extra funcs) and an interface which can be used on the sim and a device or two devices. The purpose is to save data to the parse system, get the unique objectid for the data then send a push notice with the objectid as the custom data. Everything works but the custom data is not received by the device, so the saved data cannot be loaded using the objectid. This prevents a DrawSomething or Words With Friends style game.
To use this yourself, crate your certificates as described on the push tutorial, create a free test account with Parse.com and enter your various IDs into the to of the main.lua. Build the project for device and install. Run it on the sim as well. On each running app, tap either USER1 or USER2 to subscribe and login. Enter text into the text field and tap PUSH. Tapping the right PUSH should send a notification from the sim, via Parse.com, to the device. You’ll notice that the “custom” table is empty.
main.lua:
[lua]
local launchArgs = …
local Parse = require(“parse”)
local json = require(“json”)
local firstDeviceToken = “your first device token here”
local secondDeviceToken = “your second device token here”
Parse.headers[“X-Parse-Application-Id”] = “your parse app id here” – your Application-Id
Parse.headers[“X-Parse-REST-API-Key”] = “your parse rest key here” – your REST-API-Key
Parse.PushInstall.deviceToken = firstDeviceToken – device token
local deviceToken = “placeholder”
local savedDataId = nil
local loadedDataId = nil
– device model
local model = system.getInfo(“model”)
local shortModel = string.sub(model, 1, 4)
– ui
local first = display.newText ( “USER A”, 0, 0, native.systemFontBold, 30); first.x=display.contentCenterX-50; first.y = 50
local second = display.newText ( “USER B”, 0, 0, native.systemFontBold, 30); second.x=display.contentCenterX-50; second.y = 100
local inputBox = native.newTextField( 10, 130, 300, 30 )
local textBox = native.newTextBox( 10, 170, 300, 300 )
local pusha = display.newText ( “PUSH”, 0, 0, native.systemFontBold, 30); pusha.x=display.contentCenterX+70; pusha.y = 50
local pushb = display.newText ( “PUSH”, 0, 0, native.systemFontBold, 30); pushb.x=display.contentCenterX+70; pushb.y = 100
local _print = print
print = function(…)
local str = “”
for i=1, #arg do
str = str … tostring(arg[i])
end
str = str … “\n”
_print(unpack(arg))
textBox.text = textBox.text … str
end
– account
local function setA()
Parse.AccountSetup.username = “usernametest1”
Parse.AccountSetup.password = “usernametest1”
Parse.AccountSetup.email = “tester1@mailinator.com”
Parse.LocalAccount.sessionToken = nil
Parse.headers[“X-Parse-Session-Token”] = nil
if (deviceToken == “bambleweeny”) then
Parse.PushInstall.deviceToken = secondDeviceToken
else
Parse.PushInstall.deviceToken = deviceToken
end
Parse.PushInstall.channels = { strip(“tester1@mailinator.com”), }
Parse.PushMessage.channels = { strip(“tester2@mailinator.com”), }
end
local function setB()
Parse.AccountSetup.username = “testusername1”
Parse.AccountSetup.password = “testusername1”
Parse.AccountSetup.email = “tester2@mailinator.com”
Parse.LocalAccount.sessionToken = nil
Parse.headers[“X-Parse-Session-Token”] = nil
if (deviceToken == “bambleweeny”) then
Parse.PushInstall.deviceToken = firstDeviceToken
else
Parse.PushInstall.deviceToken = deviceToken
end
Parse.PushInstall.channels = { strip(“tester2@mailinator.com”), }
Parse.PushMessage.channels = { strip(“tester1@mailinator.com”), }
end
local function goSendMssg()
local function pushComplete(status, e)
if (status == “push successful”) then
print(“Message pushed successfully”)
else
print(“Push failed.”)
end
end
Parse.PushMessage.data.alert = "This is a test message from " … Parse.AccountSetup.email – ios
– Parse.PushMessage.data.title = "This is a test message from " … Parse.AccountSetup.email – android
Parse.PushMessage.data.custom = “erk!” – NEVER GETS RECEIVED!!!
Parse.pushMssg( Parse.PushMessage, pushComplete )
end
local function goLoadData()
local function loadDataComplete(status, e)
if (status == “savload successful”) then
print("Data loaded successfully: ", e)
else
print(“Load data failed.”)
end
end
Parse.query( { objectid=loadedDataId, }, loadDataComplete )
end
local function goSaveData()
local function saveDataComplete(status, e, id)
if (status == “save successful”) then
print("Data saved successfully: "…id)
savedDataId = id
goSendMssg()
else
print(“Save data failed.”)
end
end
Parse.createObj( { data=inputBox.text, }, saveDataComplete )
end
local function goInstallDev()
local function installComplete(status, e)
if (status == “install successful”) then
print(“Device installed successfully”)
else
print(“Device installation failed.”)
end
end
Parse.installDev( Parse.PushInstall, installComplete )
end
local function goSignup()
local function loginComplete(status, e)
if (status == “signup success”) then
print("Successfully signed up as "…Parse.AccountSetup.email)
goInstallDev()
else
print("Failed to sign up as "…Parse.AccountSetup.email)
end
end
Parse.signup( Parse.AccountSetup, loginComplete )
end
local function goLogin()
local function loginComplete(status, e)
if (status == “login success”) then
print("Successfully logged in as "…Parse.AccountSetup.email)
else
print("Failed to login as "…Parse.AccountSetup.email)
goSignup()
end
end
Parse.login( Parse.AccountSetup, loginComplete )
end
first:addEventListener(“tap”,function()
first:setTextColor(0,255,0)
setA()
goLogin()
native.setKeyboardFocus( nil )
return true
end)
second:addEventListener(“tap”,function()
second:setTextColor(0,255,0)
setB()
goLogin()
native.setKeyboardFocus( nil )
return true
end)
pusha:addEventListener(“tap”,function()
pusha:setTextColor(0,0,255)
setA()
goSaveData()
native.setKeyboardFocus( nil )
return true
end)
pushb:addEventListener(“tap”,function()
pushb:setTextColor(0,0,255)
setB()
goSaveData()
native.setKeyboardFocus( nil )
return true
end)
–Parse.installDev( Parse.PushInstall, installComplete )
–goLoadData()
if (loadedDataId) then
goLoadData()
end
local function dump(title, e)
print(title…"…",tostring(e))
for k,v in pairs(e) do
print(tostring(k) … “=” … tostring(v))
end
print(title…".notification…",tostring(e.notification))
if (e.notification) then
for k,v in pairs(e.notification) do
print(tostring(k) … “=” … tostring(v))
end
end
print(title…".custom…",tostring(e.custom))
if (e.custom) then
for k,v in pairs(e.custom) do
print(tostring(k) … “=” … tostring(v))
end
end
end
if launchArgs and launchArgs.notification then
–[[ notification table contains:
launchArgs.notification.type - “remote”
launchArgs.notification.name - “notification”
launchArgs.notification.sound - “sound file or ‘default’”
launchArgs.notification.alert - “message specified during push”
launchArgs.notification.badge - “5” – badge value that was sent
launchArgs.notification.applicationstate - “inactive”
]]–
dump(“Launch”, launchArgs)
native.showAlert( “launchArgs”, json.encode( launchArgs ), { “OK” } ) – .notification
loadedDataId = launchargs.notification.dataid
end
– notification listener
local function onNotification( event )
if event.type == “remoteRegistration” then
deviceToken = event.token
native.showAlert( “remoteRegistration”, event.token, { “OK” } )
elseif event.type == “remote” then
dump(“Notice”, event)
native.showAlert( “remote”, json.encode( event ), { “OK” } )
end
end
Runtime:addEventListener( “notification”, onNotification )
[/lua]
parse.lua:
[lua]
local Parse = {}
local value = require (“json”)
local url = require(“socket.url”) – http://w3.impa.br/~diego/software/luasocket/url.html
–Parse data fields
local playerEmail = {}
playerEmail.email = nil
local request = nil
Parse.request = request
local baseUrl = “https://api.parse.com/1/”
local class = {}
class.users = “users”
class.login = “login”
class.reset = “requestPasswordReset”
class.game = “classes/game”
class.design = “classes/Design”
class.installation = “installations”
class.push = “push”
–sign up with Parse.com to obtain Application ID and REST API Key
local headers = {}
headers[“X-Parse-Application-Id”] = nil – your Application-Id
headers[“X-Parse-REST-API-Key”] = nil – your REST-API-Key
headers[“X-Parse-Session-Token”] = nil – session token for altering User object
Parse.headers = headers
local params = {}
params.headers = headers
Parse.params = params
–get from player input or local storage
local AccountSetup = {
username = “testusername1”,
password = “testusername1”,
email = “tester1@mailinator.com”,
}
Parse.AccountSetup = AccountSetup
local LocalAccount = {
username = “testusername1”,
password = “testusername1”,
email = “tester1@mailinator.com”,
emailVerified = false, – read-only response field
objectId = nil, – read-only response field
createdAt = nil, – read-only response field
updatedAt = nil, – read-only response field
sessionToken = nil, – read-only response field
experience = nil,
credits = nil
– define additional fields as necessary
}
Parse.LocalAccount = LocalAccount
function strip(str)
str = “A” … string.gsub( str, “@”, “_” )
str = string.gsub( str, “%.”, “_” )
print(str)
return str
end
local PushInstall = {
deviceType = “ios”,
deviceToken = “blargle”,
channels = { strip(“tester1@mailinator.com”), },
badge = 0,
}
Parse.PushInstall = PushInstall
local PushMessage = {
channels = {},
data = {
alert = "This is a test message from ", – ios
title = "This is a test message from ", – android
badge = “Increment”,
},
}
Parse.PushMessage = PushMessage
local createData = {[“entry”] = “object, x, y, width, height”}
Parse.createData = createData
local updateData = {[“credits”] = 100}
Parse.updateData = updateData
local function networkListener( event )
local response = nil
print (request … " response: ", event.response)
if ( event.isError ) then
print( “Network error!”)
return “network problem”
else
print ("Status code: ", event.status)
response = value.decode( event.response )
if response[“error”] then
print (response[“error”])
if (response[“code”] == 101 and request == “login”) then
print (“Invalid login parameters”)
return “invalid login”
end
if (response[“code”] == 202 and request == “signup”) then
print (“Username taken”)
return “username taken”
end
if (response[“code”] == 206 and request == “updateObj”) then
print (“Must be logged in to update object”)
end
return “network problem”
elseif (request == “signup”) then
– pass player account info to LocalAccount
for k,v in pairs(AccountSetup) do
LocalAccount[k] = v
end
– pass parse response to LocalAccount
for k,v in pairs(response) do
LocalAccount[k] = v
end
– set playeremail table in case password reset needs to be called
playerEmail.email = LocalAccount[“email”]
return “signup success”
elseif (request == “login”) then
for k,v in pairs(response) do
LocalAccount[k] = v
end
–set sessionToken
headers[“X-Parse-Session-Token”] = LocalAccount.sessionToken
return “login success”
elseif (request == “createObj” or request == “updateObj”) then
–get response
for k,v in pairs(response) do
LocalAccount[k] = v
end
–now update
for k,v in pairs (updateData) do
LocalAccount[k] = v
end
return “save successful”, response.objectId
elseif (request == “updateObj” or request == “getObj”) then
for k,v in pairs(response) do
LocalAccount[k] = v
end
return “save successful”
elseif (request == “findObj”) then
–parse table returned in response[“results”][1]
if (response[“results”][1]) then
for k,v in pairs(response[“results”][1]) do
LocalAccount[k] = v
print (“k”, k, “v”, v)
end
else
print (“Object not found”)
end
elseif (request == “deleteObj”) then
–delete local object
for k,v in pairs(LocalAccount) do
LocalAccount[k] = nil
end
elseif (request == “installDev”) then
for k,v in pairs(LocalAccount) do
LocalAccount[k] = nil
end
return “install successful”
elseif (request == “pushMssg”) then
for k,v in pairs(LocalAccount) do
LocalAccount[k] = nil
end
return “push successful”
elseif (request == “query”) then
for k,v in pairs(response) do
print(k,v)
end
return “query successful”, response
end
end
–reset reference to calling function
request = nil
print ("###")
print (“LocalAccount: “)
for k,v in pairs(LocalAccount) do
print (k, “:”, v)
end
print (”###”)
end
local function getStoredUsername ()
local path = system.pathForFile( “usr.txt”, system.DocumentsDirectory )
– io.open opens a file at path. returns nil if no file found
local file, err = io.open( path, “r” )
if (file) then
local storedName = file:read( “*a” )
return storedName
else
print ("Failed: ", err)
return nil
end
end
Parse.getStoredUsername = getStoredUsername
local function signup( obj, callback )
if (not obj.username or not obj.password or not obj.email) then
print (“Missing login data”)
else
headers[“Content-Type”] = “application/json”
params.body = value.encode ( obj )
request = “signup”
local function listener(e)
local status = networkListener(e)
if (callback) then
callback(status, e)
end
end
network.request( baseUrl … class.users, “POST”, listener, params)
end
end
Parse.signup = signup
local function login( obj, callback )
if (not obj.username or not obj.password) then
print (“No data available for login”)
else
headers[“Content-Type”] = “application/x-www-form-urlencoded”
params.body = nil
local query = “?username=” … obj.username … “&password=” … obj.password
request = “login”
– print( baseUrl … class.login … query)
local function listener(e)
local status = networkListener(e)
if (callback) then
callback(status, e)
end
end
network.request( baseUrl … class.login … query, “GET”, listener, params )
end
end
Parse.login = login
local function resetPassword (obj)
if (obj.email) then
headers[“Content-Type”] = “application/json”
request = “resetPassword”
params.body = value.encode ( obj )
network.request( baseUrl … class.reset, “POST”, networkListener, params)
else
print (“No email available”)
end
end
Parse.resetPassword = resetPassword
local function createObj( data, callback )
headers[“Content-Type”] = “application/json”
params.body = value.encode ( data )
request = “createObj”
print ( baseUrl … class.design … “/”)
for k,v in pairs(data) do
print ("updateObj: ", k, “:”, v)
end
local function listener(e)
local status, id = networkListener(e)
if (callback) then
callback(status, e, id)
end
end
network.request( baseUrl … class.design … “/”, “POST”, listener, params )
end
Parse.createObj = createObj
local function updateObj (obj, data)
if (obj.objectId) then
headers[“Content-Type”] = “application/json”
params.body = value.encode ( data )
request = “updateObj”
print (baseUrl … class.users … “/” … obj.objectId)
for k,v in pairs(data) do
print ("updateObj: ", k, “:”, v)
end
network.request( baseUrl … class.users … “/” … obj.objectId, “PUT”, networkListener, params)
else
print (“No object to update”)
end
end
Parse.updateObj = updateObj
local function deleteObj (obj)
if (obj.objectId) then
headers[“Content-Type”] = “application/json”
request = “deleteObj”
network.request( baseUrl … class.users … “/” … obj.objectId, “DELETE”, networkListener, params)
else
print (“No object to delete”)
end
end
Parse.deleteObj = deleteObj
local function getObj (obj)
if (obj.objectId) then
headers[“Content-Type”] = “application/json”
params.body = nil
request = “getObj”
network.request( baseUrl … class.users … “/” … obj.objectId, “GET”, networkListener, params)
print (baseUrl … class.users … “/” … obj.objectId)
else
print (“Not logged in.”)
end
end
Parse.getObj = getObj
local function findObj (obj)
local storedName = getStoredUsername()
if (not obj.username and not storedName) then
print (“Not logged in.”)
return
elseif (not obj.username and storedName) then
obj.username = storedName
print (“Got stored name”)
elseif (obj.username and storedName and obj.username ~= storedName) then
–search updated name
obj.username = storedName
end
print ("obj.username: ", obj.username)
–find object by username when objectId is not known
headers[“Content-Type”] = “application/json”
params.body = nil
local table = {}
–find this key/value pair
table.username = obj.username
local string = “?where=” … url.escape(value.encode(table))
print ("LOOKING FOR: ", baseUrl … class.users … string)
request = “findObj”
network.request( baseUrl … class.users … string, “GET”, networkListener, params)
print (baseUrl)
end
Parse.findObj = findObj
local function installDev( obj, callback )
headers[“Content-Type”] = “application/json”
params.body = value.encode( obj )
request = “installDev”
print ( baseUrl … class.installation … “/”)
for k,v in pairs(obj) do
print ("installDev: ", k, “:”, v)
end
local function listener(e)
local status = networkListener(e)
if (callback) then
callback(status, e)
end
end
network.request( baseUrl … class.installation … “/”, “POST”, listener, params )
end
Parse.installDev = installDev
local function pushMssg( obj, callback )
headers[“Content-Type”] = “application/json”
params.body = value.encode( obj )
request = “pushMssg”
print ( baseUrl … class.push … “/”)
for k,v in pairs(obj) do
print ("pushMssg: ", k, “:”, v)
end
local function listener(e)
local status = networkListener(e)
if (callback) then
callback(status, e)
end
end
network.request( baseUrl … class.push … “/”, “POST”, listener, params )
end
Parse.pushMssg = pushMssg
local function query(obj)
headers[“Content-Type”] = “application/json”
params.body = nil
local tbl = {}
–find this key/value pair
tbl.username = obj.username
local str = “?where=” … url.escape(value.encode(obj))
print ("LOOKING FOR: ", baseUrl … class.design … str)
request = “findObj”
network.request( baseUrl … class.design … str, “GET”, networkListener, params)
print (baseUrl)
end
Parse.query = query
– set up buttons
local function buttonHandler ( event )
local method = event.target.method
if event.phase == “ended” then
–pass other objects to these functions if data is not on user object
if method == “signup” then signup (AccountSetup)
elseif method == “login” then login (LocalAccount)
elseif method == “createObj” then createObj (LocalAccount, createData)
elseif method == “getObj” then getObj (LocalAccount)
elseif method == “findObj” then findObj (LocalAccount)
elseif method == “updateObj” then updateObj (LocalAccount, updateData)
elseif method == “deleteObj” then deleteObj (LocalAccount)
elseif method == “resetPassword” then resetPassword (playerEmail)
end
end
return true
end
–[[
local buttons = { “signup”, “login”, “createObj”, “getObj”, “findObj”, “updateObj”, “deleteObj”, “resetPassword” }
for i=1,#buttons do
local b = display.newText ( buttons[i], 30, 24*i, native.systemFontBold, 12)
b.method = buttons[i]
b:addEventListener ( “touch”, buttonHandler )
end
]]–
return Parse
[/lua] [import]uid: 8271 topic_id: 35906 reply_id: 335906[/import]