Endpoints generated client library - android

My problem is that I migrated to Endpoints v2, and at some point down the line my GCM registration code stopped working.
Stopped working? More specifically, the generated client library is attempting to send a POST request in the form provided in the top line of this image:
The second line is what happens when I send the request myself manually with Postman (changing it so that it sends the data in the URL fragment instead of in the query string). This works, and is added to my database.
The registration is sent using the standard API builder:
Registration.Builder builder = new Registration.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null)
.setRootUrl("https://"+Constants.PROJECT_ID+".appspot.com/_ah/api/");
regService = builder.build();
regService.registerDevice(gcmRegistrationId).execute();
The endpoint itself looks like this:
#ApiMethod(name = "registerDevice", httpMethod = "post")
public void registerDevice(#Named("regId") String regId) {
if(findRecord(regId) != null) {
log.info("Device " + regId + " already registered, skipping register");
return;
}
RegistrationRecord record = new RegistrationRecord();
record.setRegId(regId);
ofy().save().entity(record).now();
}
How can this be resolved?
My code is being deployed and generated with the following commands:
gradlew endpointsOpenApiDocs
gcloud endpoints services deploy backend\build\endpointsOpenApiDocs\openapi.json
gradlew appengineDeploy
gradlew endpointsClientLibs

If you want the parameter to be a query string, it should be marked #Nullable as well. This will tell take the parameter out of the path. Looks like there is some mismatch between the configuration in the old and new frameworks, but it is more correct to use #Nullable for query parameters and omit it for path parameters.

Related

Using VB.NET to sent notification to android emulator get error 401

I'm writing VB.NET code to send notification to android Emulator. I can successfully send test message from the firebase control. However, it failed when I tried to send message via VB.NET code in my local machine and get error "The remote server returned an error: (401) Unauthorized".
I have tried looking at the following link:
FCM (Firebase Cloud Messaging) Push Notification with Asp.Net
and following the instructions but it still not working.
Here is my code:
Imports System.Net
Imports Newtonsoft.Json
Public Class Notification
Public Sub SendNotification(ByVal deviceIDList As List(Of String), ByVal title As String, ByVal bodyMsg As String)
Dim fcmPath As String = "https://fcm.googleapis.com/fcm/send"
Dim serverKey As String = "AIzaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxoCAeI"
Dim senderID As String = "35xxxxxxx37"
Dim request As HttpWebRequest = CType(HttpWebRequest.Create(fcmPath), HttpWebRequest)
With request
.Method = "POST"
.ContentType = "application/json"
.Headers.Add(String.Format("Authorization: key={0}", serverKey))
.Headers.Add(String.Format("Sender: id={0}", senderID))
End With
Using streamWriter = New StreamWriter(request.GetRequestStream())
Dim webObject As New WebRequestFcmData
With webObject
.registration_ids = deviceIDList
.notification.title = title
.notification.body = bodyMsg
.notification.content_available = True
.notification.sound = "default"
.notification.priority = "high"
End With
Dim body = JsonConvert.SerializeObject(webObject)
With streamWriter
.Write(body)
.Flush()
.Close()
End With
End Using
Dim httpResponse = CType(request.GetResponse(), HttpWebResponse)
Using streamReader As New StreamReader(httpResponse.GetResponseStream)
Dim result = streamReader.ReadToEnd
End Using
End Sub
End Class
Public Class WebRequestFcmData
Public Property registration_ids As List(Of String)
Public Property notification As New NotificationData
End Class
Public Class NotificationData
Public Property body As String
Public Property content_available As Boolean
Public Property priority As String
Public Property title As String
Public Property sound As String
End Class
The error occurred at the line:
Dim httpResponse = CType(request.GetResponse(), HttpWebResponse)
Here is the server key and sender ID that I use:
Updated:
I tried sending web request from Postman application and it also gave the same error (401: Unauthorized) as shown in the figure below:
OK. I made a silly mistake by using API Key which is not actual Server key. Even though I have read that I should go to cloud messaging tab in project setting, I misunderstood that I have to look in cloud messaging tab in the side bar which is wrong. Here is the step where I found server key:
Click on the setting button near Project Overview
Choose the first option (Project setting)
Click on the second tab (Cloud messaging)
Use the server key and sender ID in this page
At first, I tried looking for server key in cloud messaging tab in the sidebar which is wrong location.

What does Device Id mean Azure Push Notifications in Xamarin Android? How to get it?

We are using Azure Mobile Services to Push notifications to a Xamarin Android and a Xamarin iOS and a Windows Universal App. The Windows Universal App has plenty of documentation around what we need, although we haven’t had a chance to implement it yet. However, both Xamarin Android and iOS are missing all documentation around Push Notifications. If you go to http://azure.microsoft.com/en-us/documentation/services/mobile-services/ and select Xamarin Android or Xamarin iOS and .NET Backend there are zero links for documentation around these APIs. After digging around a ton yesterday I found this: http://azure.microsoft.com/en-us/documentation/articles/mobile-services-dotnet-backend-xamarin-android-get-started-push/ and http://azure.microsoft.com/en-us/documentation/articles/mobile-services-dotnet-backend-xamarin-ios-get-started-push/ both which were last updated in September of last year. The documentation was promised to be updated over 5 months ago.
When I use the Xamarin Component from Microsoft for Azure Mobile Services: http://components.xamarin.com/view/azure-mobile-services/ I am able to get the MobileServiceClient up and running, but not the Push notifications.
The API:
Push pushManager = MobileService.GetPush();
string deviceId = "what is this???";
//Option 1:
pushManager.RegisterNativeAsync(deviceId);
//Option 2:
GcmRegistration googleNotificationRegistration = new GcmRegistration(deviceId);
pushManager.RegisterAsync(googleNotificationRegistration);
Documentation I’m using:
Push.RegisterAsync:
https://msdn.microsoft.com/en-us/library/microsoft.windowsazure.mobileservices.push.registerasync.aspx
GcmRegistration: I can’t find any documentation for this class
Registration (Base class for GcmRegistration):
https://msdn.microsoft.com/en-us/library/microsoft.windowsazure.mobileservices.registration.aspx
Note: the parameter for Registration is not named deviceId it is named channelUri
Push.RegisterNativeAsync:
https://msdn.microsoft.com/en-us/library/dn643553.aspx
Note: the parameter of RegisterNativeAsync is not named deviceId it is named channelUri
My question is simple:
What is deviceId supposed to be? And how do I get it?
All the documentation above is for Winodws Universal Apps not for Xamarin Apps on Mono.
In the writing up of this question I have found articles about "Get Started with Notification Hubs":
Xamarin iOS - http://azure.microsoft.com/en-us/documentation/articles/partner-xamarin-notification-hubs-ios-get-started/
Xamarin Android - http://azure.microsoft.com/en-us/documentation/articles/partner-xamarin-notification-hubs-android-get-started/
Are these the example I should be using? They look old and the Android one mentions nothing about Azure Mobile Services. Should I not even be using the Azure Mobile Services Xamarin Component for Android?
tl;dr
deviceId should be just the GCMRegistrationId.
I looked into the source code of the implementations of the component DLLs and also Android SDKs.
Firstly, let's take a look to your option 1 and option 2 behind the scene. Basically both eventually do the same job of creating a GcmRegistration and passing it the internal RegistrationManager.
public Task RegisterAsync (Registration registration)
{
if (registration == null) {
throw new ArgumentNullException ("registration");
}
if (string.IsNullOrWhiteSpace (registration.PushHandle)) {
throw new ArgumentNullException ("registration.deviceId");
}
return this.RegistrationManager.RegisterAsync (registration);
}
public Task RegisterNativeAsync (string deviceId, IEnumerable<string> tags)
{
if (string.IsNullOrWhiteSpace (deviceId)) {
throw new ArgumentNullException ("deviceId");
}
GcmRegistration registration = new GcmRegistration (deviceId, tags);
return this.RegistrationManager.RegisterAsync (registration);
}
Then, one of the API calls that I can find involving the Registration.PushHandle (which is the deviceId you passed) is as below
public async Task<IEnumerable<Registration>> ListRegistrationsAsync (string deviceId)
{
MobileServiceHttpResponse mobileServiceHttpResponse = await this.client.HttpClient.RequestAsync (HttpMethod.Get, string.Format ("/push/registrations?deviceId={0}&platform={1}", new object[] {
Uri.EscapeUriString (deviceId),
Uri.EscapeUriString (Platform.Instance.PushUtility.GetPlatform ())
}), this.client.CurrentUser, null, true, null, MobileServiceFeatures.None);
return JsonConvert.DeserializeObject<IEnumerable<Registration>> (mobileServiceHttpResponse.Content, new JsonConverter[] {
new RegistrationConverter ()
});
}
I have then switched to Android Mobile Services SDK to look for similar code to find some hints. Sadly, it is found called pnsHandle in android but still no hints what it is.
/**
* Registers the client for native notifications with the specified tags
* #param pnsHandle PNS specific identifier
* #param tags Tags to use in the registration
* #return The created registration
* #throws Exception
*/
public Registration register(String pnsHandle, String... tags) throws Exception {
if (isNullOrWhiteSpace(pnsHandle)) {
throw new IllegalArgumentException("pnsHandle");
}
Registration registration = PnsSpecificRegistrationFactory.getInstance().createNativeRegistration(mNotificationHubPath);
registration.setPNSHandle(pnsHandle);
registration.setName(Registration.DEFAULT_REGISTRATION_NAME);
registration.addTags(tags);
return registerInternal(registration);
}
Finally, I guess the below example code from http://azure.microsoft.com/en-us/documentation/articles/mobile-services-dotnet-backend-android-get-started-push/#update-app should be calling the same API which now explain everything, i.e. deviceId is just the GCMRegistrationId.
#Override
public void onRegistered(Context context, final String gcmRegistrationId) {
super.onRegistered(context, gcmRegistrationId);
new AsyncTask<Void, Void, Void>() {
protected Void doInBackground(Void... params) {
try {
ToDoActivity.mClient.getPush().register(gcmRegistrationId, null);
return null;
}
catch(Exception e) {
// handle error
}
return null;
}
}.execute();
}

cloudBackend.setCredential not setting createdBy/updatedBy/owner properties of CloudEntity

I am using mobile backend starter and I am trying to update an entity when using the secured by id setting. I keep getting the error
com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized
{
"code": 401,
"errors": [
{
"domain": "global",
"location": "Authorization",
"locationType": "header",
"message": "Insuffient permission for updating a CloudEntity: CE:123456 by: USER:123456",
"reason": "required"
}
],
"message": "Insuffient permission for updating a CloudEntity: CE: 123456 by: USER:123456"
}
The documentation (https://cloud.google.com/developers/articles/mobile-backend-starter-api-reference/#ciagaa) states
In the code below, the backend allows the call in “Secured by Client
ID” mode. It also sets createdBy/updatedBy/owner properties of
CloudEntity automatically
GoogleAccountCredential credential =
GoogleAccountCredential.usingAudience(this, "<Web Client ID>");
credential.setSelectedAccountName("<Google Account Name>");
cloudBackend.setCredential(credential);
So I wrote the following code
mCloudBackend = new CloudBackendMessaging(this);
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(this, Consts.AUTH_AUDIENCE);
mCloudBackend.setCredential(credential);
String accountName =
mCloudBackend.getSharedPreferences().getString(
Consts.PREF_KEY_ACCOUNT_NAME, null);
credential.setSelectedAccountName(accountName);
mCloudBackend.setCredential(credential);
newPost.setId(updateRide);
mCloudBackend.update(newPost, handler);
Unfortunately this is giving the error above. However, the update is going through as I can see changes in entity when I query the datastore. The problem seems to come from the fact that the createdBy/updatedBy/owner properties are set to null and so are not being set automatically.
I have seen other questions where the answer has been to query the entity prior to the update, use this to set the aforementioned properties and then perform the update. I would rather avoid this as it seems like an unnecessary call to the datastore. So my question is how to I get the GoogleAccount createdBy updatedBy and owner properties?
I faced similar problem while playing with the mobile backend starter source.And even though I followed the answers provided in this link,I wasn't able to resolve the issue.However,what I did was to grab the mobile backend source code and make some modifications.Grab the code and in the CrudOperations.java file,you will see this method
private Map<String, Entity> findAndUpdateExistingEntities(EntityListDto cdl, User user)
throws UnauthorizedException{
// create a list of CEs with existing Id
EntityListDto entitiesWithIds = new EntityListDto();
Map<String, EntityDto> entitiesWithIdMap = new HashMap<String, EntityDto>();
for (EntityDto cd : cdl.getEntries()) {
if (cd.getId() != null) {
entitiesWithIds.add(cd);
entitiesWithIdMap.put(cd.getId(), cd);
}
}
// try to get existing CEs
Map<String, Entity> existingEntities = getAllEntitiesByKeyList(entitiesWithIds
.readKeyList(user));
// update existing entities
for (String id : existingEntities.keySet()) {
// check ACL
Entity e = existingEntities.get(id);
SecurityChecker.getInstance().checkAclForWrite(e, user);
// update metadata
EntityDto cd1 = entitiesWithIdMap.get(id);
cd1.setUpdatedAt(new Date());
if (user != null) {
cd1.setUpdatedBy(user.getEmail());
}
// update the entity
cd1.copyPropValuesToEntity(e);
}
return existingEntities;
}
From the above code,comment out SecurityChecker.getInstance().checkAclForWrite(e, user);
and the throws UnAuthorizedException lines and redeploy your backend.Doing so will make all users of your app able to make updates to the concerned entity.This could be risky if you are strictly concerned about ownership.So,consider your security concerns before taking this approach.Haven done that,you can now freely update the concerned cloud entity.Remember to make as default your newly deployed backend on the server side.

Google Plus Single Sign On Server Flow - Google_AuthException Error fetching OAuth2 access token, message: 'invalid_grant'

UPDATE 27th January 2013
I have now resolved this, Please check the accepted answer.
I am having trouble to get my refresh token and my access token when using the server side flow between my Android Application and my PHP server.
So I have managed to get my One Time Code by using the below:
AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
Bundle appActivities = new Bundle();
appActivities.putString(GoogleAuthUtil.KEY_REQUEST_VISIBLE_ACTIVITIES,
"http://schemas.google.com/AddActivity");
String scopes = "oauth2:server:client_id:" + SERVER_CLIENT_ID +
":api_scope:" + SCOPE_STRING;
try {
code = GoogleAuthUtil.getToken(
OneTimeCodeActivity.this, // Context context
mPlusClient.getAccountName(), // String accountName
scopes, // String scope
appActivities // Bundle bundle
);
} catch (IOException transientEx) {
// network or server error, the call is expected to succeed if you try again later.
// Don't attempt to call again immediately - the request is likely to
// fail, you'll hit quotas or back-off.
System.out.println(transientEx.printStactTrace());
return "Error";
} catch (UserRecoverableAuthException e) {
// Recover
code = null;
System.out.println(e.printStackTrace());
OneTimeCodeActivity.this.startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
} catch (GoogleAuthException authEx) {
// Failure. The call is not expected to ever succeed so it should not be
// retried.
System.out.println(authEx.printStackTrace());
return "Error";
} catch (Exception e) {
System.out.println(authEx.printStackTrace());
}
}
Which will then store the token in the variable "code" and I call up the async task as
task.execute();
The code above will always bring up a popup message and throw UserRecoverableAuthException Need Permission that requires the user to grant offline access, which means the above will need to be called twice to retrieve the code and store it in "code"
I am now trying to send this across to my server which is implemented in PHP.
I have used the quick start https://developers.google.com/+/quickstart/php and managed to get that working.
In here, there is a sample signin.php
In here and according to the documentation this already implements a One Time Authorisation Server Side Flow.
So now my problem is sending this One Time Code to the server.
I used the photohunt Android Auth example for this located here.
https://github.com/googleplus/gplus-photohunt-client-android/blob/master/src/com/google/plus/samples/photohunt/auth/AuthUtil.java
I used the "authorization" method of the code and called up signin.php/connect through a post method shown below
$app->post('/connect', function (Request $request) use ($app, $client) {
$token = $app['session']->get('token');
if (empty($token)) {
// Ensure that this is no request forgery going on, and that the user
// sending us this connect request is the user that was supposed to.
if ($request->get('state') != ($app['session']->get('state'))) {
return new Response('Invalid state parameter', 401);
}
// Normally the state would be a one-time use token, however in our
// simple case, we want a user to be able to connect and disconnect
// without reloading the page. Thus, for demonstration, we don't
// implement this best practice.
//$app['session']->set('state', '');
$code = $request->getContent();
// Exchange the OAuth 2.0 authorization code for user credentials.
$client->authenticate($code);
$token = json_decode($client->getAccessToken());
// You can read the Google user ID in the ID token.
// "sub" represents the ID token subscriber which in our case
// is the user ID. This sample does not use the user ID.
$attributes = $client->verifyIdToken($token->id_token, CLIENT_ID)
->getAttributes();
$gplus_id = $attributes["payload"]["sub"];
// Store the token in the session for later use.
$app['session']->set('token', json_encode($token));
$response = 'Successfully connected with token: ' . print_r($token, true);
}
return new Response($response, 200);
});
Now when I send the code using the above implementation, I get an 500 messages that says the below
Google_AuthException Error fetching OAuth2 access token, message: 'invalid_grant'
in ../vendor/google/google-api-php-client/src/auth/Google_OAuth2.php line 115
at Google_OAuth2->authenticate(array('scope' => 'https://www.googleapis.com/auth/plus.login'), '{ "token":"xxxxxxxx"}') in ../vendor/google/google-api-php-client/src/Google_Client.php line 131
at Google_Client->authenticate('{ "token":"xxxxxxx"}') in ../signin.php line 99
at {closure}(object(Request))
at call_user_func_array(object(Closure), array(object(Request))) in ../vendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpKernel.php line 117
at HttpKernel->handleRaw(object(Request), '1') in ../vendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpKernel.php line 61
at HttpKernel->handle(object(Request), '1', true) in ../vendor/silex/silex/src/Silex/Application.php line 504
at Application->handle(object(Request)) in ../vendor/silex/silex/src/Silex/Application.php line 481
at Application->run() in ../signin.php line 139
Funny enough I have had to worked once where I did receive a 200, but I cannot recreate it.
So I know I have definitely got the implementation wrong, but I have no clue on how to send it and get my refresh token. I can't find anywhere on the web that explains this. Is someone able to help me please.
UPDATE 16 Jan 2014
Using https://www.googleapis.com/oauth2/v1/tokeninfo?access_token= I can see that the token being produced from getToken is valid and is indeed valid for 1 hour.
I can confirm the json formation is correct by changing the way I am inputting into the Post request and if I don't do it properly I get a total failure.
Now I am going deeper into the php and look at this section Google_OAuth2.php line 115 where it is breaking it is throwing a Google_AuthException. The code is below and this is provided in the quick starter pack
/**
* #param $service
* #param string|null $code
* #throws Google_AuthException
* #return string
*/
public function authenticate($service, $code = null) {
if (!$code && isset($_GET['code'])) {
$code = $_GET['code'];
}
if ($code) {
// We got here from the redirect from a successful authorization grant, fetch the access token
$request = Google_Client::$io->makeRequest(new Google_HttpRequest(self::OAUTH2_TOKEN_URI, 'POST', array(), array(
'code' => $code,
'grant_type' => 'authorization_code',
'redirect_uri' => $this->redirectUri,
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret
)));
if ($request->getResponseHttpCode() == 200) {
$this->setAccessToken($request->getResponseBody());
$this->token['created'] = time();
return $this->getAccessToken();
} else {
$response = $request->getResponseBody();
$decodedResponse = json_decode($response, true);
if ($decodedResponse != null && $decodedResponse['error']) {
$response = $decodedResponse['error'];
}
throw new Google_AuthException("Error fetching OAuth2 access token, message: '$response'", $request->getResponseHttpCode());
}
}
$authUrl = $this->createAuthUrl($service['scope']);
header('Location: ' . $authUrl);
return true;
}
I edit the code above to make sure the code, the client id and secret were correct and they were. So that is where I am now, I don't think it is scope issues as well as I hard coded it in the client setup and still does not work. Not too sure.
UPDATE 23rd January
OK, I think it is a time issue. I used https://developers.google.com/+/photohunt/android and base my design on the BaseActivity in the Photohunt using the AuthUtil, and I get invalid grant on my server. How do I move the time back on my server in code. I read somewhere I can do time() - 10 somewhere but not sure where...
It sounds like you may be sending the same authorization code multiple times. On Android GoogleAuthUtil.getToken() caches any tokens that it retrieves including authorization codes.
If you ask for a second code without invalidating the previous code, GoogleAuthUtil will return the same code. When you try to exchange a code on your server which has already been exchanged you get the invalid_grant error. My advice would be to invalidate the token immediately after you retrieve it (even if you fail to exchange the code, you are better off getting a new one than retrying with the old one).
code = GoogleAuthUtil.getToken(
OneTimeCodeActivity.this, // Context context
mPlusClient.getAccountName(), // String accountName
scopes, // String scope
appActivities // Bundle bundle
);
GoogleAuthUtil.invalidateToken(
OneTimeCodeActivity.this,
code
);
invalid_grant can be returned for other reasons, but my guess is that caching is causing your problem since you said it worked the first time.
This issue is now resolved. This was due to the implementation on the One Time Code exchange with the server
As specified in the my issue above, I used the photohunt example to do the exchange with my server. The Android code can be found on the below link
https://github.com/googleplus/gplus-photohunt-client-android/blob/master/src/com/google/plus/samples/photohunt/auth/AuthUtil.java
One line 44 it reads this
byte[] postBody = String.format(ACCESS_TOKEN_JSON, sAccessToken).getBytes();
This will only work if on the server side you handle the JSON. I did not.
When calling up $client->authenticate($code); in php, $code had a JSON string and therefore when calling https://accounts.google.com/o/oauth2/token the authorization code was wrong.
So it was easy as I was not sending the code in the right format.
I found this out when digging and testing https://accounts.google.com/o/oauth2/token and created a manual cURL to test the token.
As provided in the Google+ API it was stated that all examples included a One Time Code exchange, but I think the code across all platform are not consistent and one has to double check themselve to make sure everything flows correctly, which was my mistake.

C2DM with App Engine Python returns 401 error

I'm tyring to send a message to my mobile. Via browser I call the method that does this operation, I've logged the registrationId, authToken, etc.. and this is correct, because I tested in a local server and the message has been send to my phone using these keys.
However on App Engine, I have a 401 error on the result of the urlfetch.fetch for 'https://android.clients.google.com/c2dm/send'.
Or if this is a problem with authentication. I doubt it is the problem above, because the method is called, and the error happens right in the end of the method in my App Engine server.
Here is how I make the request to the C2DM servers:
params = {
'registration_id':registrationId,
'collapse_key':0,
'data.payload':encoded_msg
}
paramsByte = urllib.urlencode(params)
logging.info(registrationId)
url = 'https://android.clients.google.com/c2dm/send'
logging.info(token)
result = urlfetch.fetch(url=url,
payload=paramsByte,
method=urlfetch.POST,
headers={'Content-Type':'application/x-www-form-urlencoded',
'Authorization':'GoogleLogin auth='+token}
)
Any help would be appreciated. Thanks.
UPDATE
Now the client is running in a hosting server as suggested, and the
401 error happens when contacting
'https://android.clients.google.com/c2dm/send'.
However when using the following command on terminal with the same token and regId, it works.
curl --header "Authorization: GoogleLogin auth=your_authenticationid"
"https://android.apis.google.com/c2dm/send" -d
registration_id=your_registration -d "data.payload=payload" -d
collapse_key=0
Client code calling the method in server:
$.getJSON('http://myapp.appspot.com/method?userId='+userId+'&message='+theMessage+'&callback=?',
function(data)
{
console.log(data);
});
Full method code for server:
class PushHandler(webapp.RequestHandler):
'''This method sends the message to C2DM server to send the message to the phone'''
def get(self):
logging.info('aqui dentro')
userId = self.request.get('userId')
message = self.request.get('message')
callback = self.request.get('callback')
token = getToken(self) #this is a method I've implemented to get the token from C2DM servers by passing the SenderId and Password
registrationId = ''
contactNumber = ''
# Get the registrationId to send to the C2DM server to know which
# device it may send the message
regQuery = C2DMUser.all()
regQuery.filter('userId =', int(userId))
for k in regQuery:
registrationId = k.registrationId
# Builds the json to be sent to the phone
record_to_json = {
'userId':userId,
'message':message
}
data = []
data.append(record_to_json)
jsondata = simplejson.dumps(data) # Creates the json
# Encode the JSON String
u = unicode(jsondata, "utf-8")
encoded_msg = u.encode("utf-8")
params = {
'registration_id':registrationId,
'collapse_key':0,
'data.payload':encoded_msg
}
paramsByte = urllib.urlencode(params)
url = 'https://android.clients.google.com/c2dm/send'
logging.info(token)
result = urlfetch.fetch(url=url,
payload=paramsByte,
method=urlfetch.POST,
headers={'Content-Type':'application/x-www-form-urlencoded',
'Authorization':'GoogleLogin auth='+token}
)
data = []
params_key = { 'status_code':result.status_code }
data.append(params_key)
self.response.headers['Content-Type'] = 'application/json'
jsondata = simplejson.dumps(data)
if result.status_code == 200:
logging.info(result.status_code)
self.response.out.write('' + callback + '(' + jsondata + ')') # handle the JSONP
else:
logging.info(result.status_code)
self.response.out.write(result.status_code)
The package name of your code must match the one you gave when you signed up for the c2dm account. For Java, if you gave com.myapp when you signed up, your c2dm calls must occur within that package. Not sure how this translates to Python, though.
As far as the C2DM part is concerned, everything seems okay. If you are saying that with the same credentials it works with your local server, I am guessing that it should work on App Engine.
As far as the XMLHttpRequest error is concerned, you can't issue requests through the XMLHttpRequest to other domains or sub-domains. So, you cannot issue your request from localhost to yourSite. A solution would be using JSONP.

Categories

Resources