B4A Library Parse Library – Push Notifications and Cloud Storage

Parse service is shutting down: http://blog.parse.com/announcements/moving-on/

Overview


This library is a rather extensive overhaul of and update to Erels’ original Parse library.

Parse is a company that provides several services for mobile applications and has just been purchased by Facebook so it looks like it should continue to be a stable and reliable service.

You create an account on Parse.com and then create what they call “Applications” which would usually correspond with individual Android applications but don’t have to, so several different Android applications could access a common body of data in a single Parse application. Within Parse applications there are “Classes” of data which look much like a database table and contain ParseObjects which look like an individual row of data in a table.

Capabilities

The two major uses for this library are as follows

1) Providing cloud based data storage and retrieval for data held in the individual Parse Applications in a simple way including querying the stored data. No need to mess with HTTP and networking, it is all done for you in an object oriented fashion.

2) Supporting Push Notifications which can be instigated both from the Parse Web Dashboard of your Parse account and, if you have enabled it in the Dashboard for that Parse application, also from devices running the corresponding Android application. Push Notifications are sent in the context of the individual Parse Applications whose Android applications have registered to receive them but individual devices, or groups of devices, may be selectively targeted by using “Channels”.

Parse offer three levels of service, the first being free as long as you keep within their limits which are one million API Requests per month, one million Push Notifications per month and one Gigabyte of storage use. You can exceed these limits without upgrading to the next paid plan, which is presently 199 US dollars per month if you register a credit card. You can exceed these limits and be charged 7 US cents per one thousand excess API Requests, 20 UC cents per one thousand Pushes and 20 US cents per one Gigabyte of excess storage. There is information on your usage of all three available in your Parse Dashboard.

An API Request is a single network operation which are the ones that raise Basic4android events from the library.

The definition of the number of Pushes is “The total number of push notifications queued for delivery to a client device”. I may be being stupid but that seems ambiguous to me and I don’t understand whether that means that the total number of Push Notifications counts as each single message sent to lots of devices or as the total number of devices to which a single message is sent. I suspect the latter. If anyone knows definitively than please post and I will amend this paragraph.

The amount of storage used is obvious and needs no explanation.

Please read the Parse Android Guide, in the Parse.com Documentation section of their web site, for more information about how to use this library. The Parse Android API document might also be useful occasionally. The mapping of this library objects methods to those of the Java API are usually obvious.

All the operations which need to access the Parse online service are done asynchronously and raise events when complete whose parameters include a Success indication. If an error occurs Success will be False and a ParseException with a message describing the error will be placed in LastException. If necessary this should be processed in the event code as there is a possibility that a further error could occur in another asynchronous call that would overwrite the existing LastException.

Note that these asynchronous operations do not necessarily complete in the order in which they are invoked. To deal with this possibility a TaskID parameter is provided in each call that can be used, if required, to identify which of several possible method calls has just completed.

Installation instructions

In order to use this library you should sign up to Parse.com, go to your Dashboard and create a new Parse application called whatever you feel like calling it. You will need two keys, Application Id and Client Key, which you will find under the Settings for your application. Both are required and need to be copied to the appropriate Process Global variables in the demo.

You also need to download the Parse Android SDK from the Downloads section of the Parse.com web site. Inside the zip file you will find a file named Parse-1.2.4.jar or similar. Copy this to your Additional Libraries folder and rename it ParseNative.jar. Also put Parse.jar and Parse.xml from the demo archive in your Additional Libraries folder.

As detailed in the help for Parse. EnableNotifications in order for your application to receive Push Notifications you need to add the following to the Manifest Editor in your project.
B4X:
SetApplicationAttribute(android:name,"anywheresoftware.b4a.objects.ParseObjectWrapper$ParseApplication")

AddApplicationText(<service android:name="com.parse.PushService" />
<receiver android:name="com.parse.ParseBroadcastReceiver">
  <intent-filter>
    <action android:name="android.intent.action.BOOT_COMPLETED" />
    <action android:name="android.intent.action.USER_PRESENT" />
  </intent-filter>
</receiver>)

Version 1.1 of this library specified the Parse keys in a Parse.Initialize method. This method no longer exists in version 1.2 and later. This is because it it was called from within an Activity, but if Android killed your process and then tried to restart the Parse Service this failed because the service started without the activity being created and so was not initialised correctly. Initialisation now occurs on Application creation and requires the library Application class name to be registered in the manifest and the Parse keys to be specified as an xml resource. When the application is loaded you will see the values in the xml file echoed to the filtered logs.

You also need to place a file called res.xml in your project Objects/res/xml folder and make it read-only. The xml folder does not exist in the project archive but will be created at your first compile. The contents of res.xml should specify your Parse keys as follows
B4X:
<!--?xml version="1.0" encoding="utf-8"?-->
<data>
   <data1 value="YourParseApplicationAppID" />
   <data2 value="YourParseApplicationClientKey" />
</data>

The demo project is already set up to receive push notifications. Try sending one from your Parse Application using the Parse Dashboard.

Run the demo and have a play.

Issues

I have found that using IE10 to send a Push from the Parse Dashboard usually causes the Push to be sent twice, you will see this in the Dashboard list of pushes sent and also at the device and of course they both count towards your free total. Chrome appears to work correctly and sends only one. The work-around is obvious.

The Parse library starts a service called PushService to receive the Pushes and which you can see in Settings -> Apps -> Running -> ParseDemo. Prior to Parse SDK 1.2.4 sometimes this service stopped receiving Pushes and the Process needed to be stopped using a Task Manager and restarted. Parse SDK 1.2.5 should have fixed this.

EDIT:- Version 1.2 now posted. See post #6 for details.

EDIT:- Version 1.3 now posted. See post #13 for details.

EDIT:- Version 1.4 now posted. See post #17 for details.
 

Attachments

  • Parse1.4.zip
    43.2 KB · Views: 1,318
Last edited by a moderator:

lagore

Active Member
Licensed User
Longtime User
All done as per #1 post, below is some of the unfiltered logs you can see a 'Fatal Exception' near the end in relation to "Lbolts/Task" and "bolts.tast" from the Parse change log this was added in v1.7.1 and a brand new Push API was added in v1.7.0. As you can see in the first couple of line are the App & client Keys.

Unfiltered Log
ParseApplication.onCreate xml Id = 2130903040
data null
data1 K2pwLFYtF6ihKuQKJ4FiH4XwVuLAXIjrVoLEoIMn
data2 SDu2TeuuuDGmnHTEf5SRbFYNsoYAq3ySsl2DjiGy
Rejecting re-init on previously-failed class java.lang.Class<com.parse.Parse$4>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.Parse$4>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseRequest$8>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseRequest$8>
TRAFFIC_STATS_POLL true Token 2781 num clients 13
packet count Tx=231977 Rx=228471
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseRequest$2>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseRequest$2>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseRequest$7>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseRequest$7>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$39>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$39>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$36>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$36>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$33>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$33>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$2>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$2>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$16>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$16>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$44>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$44>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$41>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$41>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$42>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$42>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$45>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$45>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$34>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$34>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$4>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$4>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$18>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$18>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$35>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$35>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$28>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$28>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$30>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$30>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$20>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$20>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$22>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$22>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$23>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$23>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$17>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$17>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$6>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$6>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$7>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$7>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$15>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$15>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$10>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseObject$10>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.GcmRegistrar$2>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.GcmRegistrar$2>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.GcmRegistrar$1>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.GcmRegistrar$1>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseInstallation$4>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseInstallation$4>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseInstallation$1>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseInstallation$1>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$33>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$33>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseInstallation$10>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$5>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$5>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseInstallation$10>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$8>
{
"version":"1.0",
"dsxDataUrl": "http://dsx.weather.com",
"dsxSecureUrl": "https://dsx-secure.weather.com",
"eventLogs":{
"enabled":false,
"tagFilter":".*",
"geocodeRequests":{
"enabled":false
},
"followMeTracking":{
"enabled":false
},
"warningLogs":{
"enabled":false
},
"errorLogs":{
"enabled":false
}
}
}
[NET] android_getaddrinfofornet+,hn 15(0x6473782e776561),sn(),hints(known),family 0,flags 4
[NET] android_getaddrinfofornet-, err=8
[NET] android_getaddrinfofornet+,hn 15(0x6473782e776561),sn(),hints(known),family 0,flags 1024
[NET] android_getaddrinfofornet-, pass to proxy
[NET] android_getaddrinfo_proxy+
[NET] android_getaddrinfo_proxy get netid:0
[NET] android_getaddrinfofornet+,hn 15(0x6473782e776561),sn(),hints(known),family 0,flags 1024
[NET] _dns_getaddrinfo+, netid:230, mark:917734
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$8>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseInstallation$5>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseInstallation$5>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$1>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$1>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseInstallation$9>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseInstallation$9>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$3>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$3>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseInstallation$7>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseInstallation$7>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseInstallation$8>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$28>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$28>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseInstallation$8>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$32>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$32>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$4>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$4>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$37>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$37>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$14>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$14>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$13>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$13>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$20>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$20>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$25>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$25>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$27>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$27>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$34>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.OfflineStore$34>
FATAL EXCEPTION: main
Process: b4a.example.parse, PID: 32416
java.lang.NoClassDefFoundError: Failed resolution of: Lbolts/Task;
at com.parse.ParseInstallation.hasCurrentInstallationAsync(ParseInstallation.java:90)
at com.parse.GcmRegistrar.updateAsync(GcmRegistrar.java:96)
at com.parse.Parse.initialize(Parse.java:163)
at anywheresoftware.b4a.objects.ParseObjectWrapper$ParseApplication.onCreate(ParseObjectWrapper.java:1164)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1024)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4947)
at android.app.ActivityThread.access$1500(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1424)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:155)
at android.app.ActivityThread.main(ActivityThread.java:5696)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
Caused by: java.lang.ClassNotFoundException: Didn't find class "bolts.Task" on path: DexPathList[[zip file "/data/app/b4a.example.parse-2/base.apk"],nativeLibraryDirectories=[/system/lib, /vendor/lib, system/vendor/lib, system/vendor/lib/egl, system/lib/hw]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
... 15 more
Suppressed: java.lang.ClassNotFoundException: bolts.Task
at java.lang.Class.classForName(Native Method)
at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
... 16 more
Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseCommandCache$4>
Rejecting re-init on previously-failed class java.lang.Class<com.parse.ParseCommandCache$4>
App crashed! Process: b4a.example.parse

A snippet from the Parse change log
1.7.1 — October 15, 2014
  • Added a new set of APIs based on Bolts Tasks.
  • Fixed a bug with ParseQuery.whereEqualTo constraint.
  • Changed ParsePush.subscribeInBackground to not send an API request if the app is already subscribed to the channel.
  • Updated documentation.
  • Other small bug fixes.

v1.7.0 — September 30, 2014
  • Deadlock & local datastore fixes
  • Brand new Push API:
  • Introducing the ParsePushBroadcastReceiver, which makes customization dramatically easier. Subscribing to and handling pushes are now decoupled. To enable the new API, register the ParsePushBroadcastReceiver and replace your PushService calls with their replacement APIs in ParsePush.
  • Notification big views are automatically created if a notification's alert is too long to display in the small view.
  • The new "uri" push option will navigate to a URI with your application in the back stack.
  • Large icons are now available by subclassing ParsePushBroadcastReceiver and implementing getLargeIcon
  • PushService.subscribe is now deprecated. See ParsePush.subscribeInBackground which exposes completion and error information.
  • PushService.unsubscribe is now deprecated. See ParsePush.unsubscribeInBackground which exposes completion and error information.
  • PushService.setDefaultCallback is now deprecated. See ParsePushBroadcastReceiver.getNotification.
  • Push icons are now specified with the com.parse.push.notification_icon or ParsePushBroadcastReceiver.getSmallIconId.
I would be interested to hear if anybody has this working with Parse V1.7 or higher.
 

monadhl

Member
Licensed User
Longtime User
i5c5Na.png



why ؟
 
Last edited:

omidaghakhani1368

Well-Known Member
Licensed User
Longtime User
Hi.
When i start sample code,get error unfortunately stop parse app.
I run project java example in eclipse and get good result but in basic4android with your library even not execute app
Please help me
 

lagore

Active Member
Licensed User
Longtime User
As I said above I believe that the new API from v1.7 has broken the 'Parse' library
 

derez

Expert
Licensed User
Longtime User
Parse uses the notification of android, with the icon in the drawable directory of the specific application.
 

omidaghakhani1368

Well-Known Member
Licensed User
Longtime User
Hi again.
Can i track the open push in notification? (when user click on notification and read it,detect it in parse.com)
 
Top