Objective-C UNIRest has no response to GET Request - objective-c

I am attempting the use the UNIRest API to run this get request in an iPhone application
https://api.guildwars2.com/v1/guild_details.json?guild_name=The%20Legacy
The code I am running is this
NSDictionary* headers = #{#"accept": #"application/json"};
NSDictionary* parameters = #{#"guild_name": #"The Legacy"};
UNIHTTPJsonResponse* response = [[UNIRest post:^(UNISimpleRequest* request) {
[request setUrl:#"https://api.guildwars2.com/v1/guild_details.json"];
[request setHeaders:headers];
[request setParameters:parameters];
}] asJson];
NSDictionary *guildInformation = response.body.JSONObject;
NSLog(#"response length: %lu", (unsigned long)[guildInformation.allValues count]);
for(NSString *key in [guildInformation allKeys]) {
NSLog(#"key: %# object: %#", key, [guildInformation objectForKey:key]);
}
I had hoped the for loop would display the response. But it seems I get no response at all when you see that the only output is,
response length: 0
I don't know the UNIRest API well enough to fix this and cannot find any good documentation for it. What am I doing wrong?

The problem seems to be that the parameters values are not correctly encoded.
As a fast workaround you can simply pass the entire constructed URL.
UNIHTTPJsonResponse* response = [[UNIRest post:^(UNISimpleRequest* request) {
[request setUrl:#"https://api.guildwars2.com/v1/guild_details.json?guild_name=The%20Legacy"];
[request setHeaders:#{#"accept": #"application/json"}];
}] asJson];
Probably the space in #"The Legacy" doesn't translate to "The%20Legacy", will do a test case before adding issue to https://github.com/Mashape/unirest-obj-c
UPDATE
Only while I was adding a TestCase for spaced values (which do work correctly) I spotted that you where using POST while you should have used GET.
UNIHTTPJsonResponse* response = [[UNIRest get:^(UNISimpleRequest* request) {

Related

data parameter is nil when i trying to fetch the data from web service using json

- (NSDictionary*)PostWebService:(NSString*)completeURL param:(NSString*)value
{
#try
{
NSString *urlStr =[completeURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
//NSString *urlPart=#"req=value";
//NSString *urlPart;
NSString *urlPart=[NSString stringWithFormat:#"req=%#", value];
NSLog(#"String %#",urlPart);
NSData *requestBody = [urlPart dataUsingEncoding:NSUTF8StringEncoding];
//NSLog(#"String %#",requestBody);
[request setHTTPBody:requestBody];
NSURLResponse *response = NULL;
NSError *requestError = NULL;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&requestError];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding] ;
NSLog(#"String %#",responseString);
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData
options:kNilOptions
error:&error];
return json;
}
#catch(NSException *e)
{
NSLog(#"reason is%#",e.reason);
}
}
and i call this method here..
-(NSDictionary*)gotvall:(NSString*)req
{
#try
{
NSString *vurl=#"some url/";
// vurl=[vurl stringByAppendingString:#"req="];
// vurl=[vurl stringByAppendingString:req];
// NSLog(#"%#",vurl);
NSDictionary *json=[self PostWebService:vurl param:req];
NSLog(#"json is%#",json);
return json;
}
#catch(NSException *e)
{
NSLog(#"%#",e.reason);
}
}
After debugging this method I got result as data parameter is nil.
Can anyone tell that what I am doing wrong here.
I got the complete url and when I run that url on browser I got the perfect data but when I printing the value of json it returns null.
You reported that your error was:
Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo=0x8d84960 {NSErrorFailingURLStringKey=%20http://www.hugosys.in/www.nett-torg.no/api/vehicl‌​e/, NSErrorFailingURLKey=%20http://www.hugosys.in/www.nett-torg.no/api/vehicle/, NSLocalizedDescription=unsupported URL, NSUnderlyingError=0x8d8bfe0 "unsupported URL"}
That %20 in your error message is a space at the start of your URL that your stringByAddingPercentEscapesUsingEncoding call converted to %20. If you remove that extra space, you should be in good shape.
A couple of other observations:
Just to warn you, your use of stringByAddingPercentEscapesUsingEncoding will correctly handle the presence of a space in the req value. But it will not properly handle the presence of certain other characters (notably & or +). If it's possible that those sorts characters might appear in the req value, you might want to remove the call to stringByAddingPercentEscapesUsingEncoding for the whole URL, and instead just use CFURLCreateStringByAddingPercentEscapes (which gives you a little more control over the percent escaping process) on just the req value. See the percentEscapeString method in this answer: Append data to a POST NSURLRequest.
In both your network request as well as your JSON parsing process, you are returning an NSError object. I might suggest that you log those values if they're ever non-nil, which will help you diagnose problems in the future.
I notice that you are using exception handling. That's not common in Objective-C. As the Programming in Objective-C guide says:
Dealing with Errors
Almost every app encounters errors. Some of these errors will be outside of your control, such as running out of disk space or losing network connectivity. Some of these errors will be recoverable, such as invalid user input. And, while all developers strive for perfection, the occasional programmer error may also occur.
If you’re coming from other platforms and languages, you may be used to working with exceptions for the majority of error handling. When you’re writing code with Objective-C, exceptions are used solely for programmer errors, like out-of-bounds array access or invalid method arguments. These are the problems that you should find and fix during testing before you ship your app.
All other errors are represented by instances of the NSError class. This chapter gives a brief introduction to using NSError objects, including how to work with framework methods that may fail and return errors. For further information, see Error Handling Programming Guide.
Bottom line, As I mentioned in the second point, you should be checking NSError return values yourself rather than relying on exceptions in Objective-C.

NSURLCache: inconsistent behaviour

I was observirng some strange behaviour of my app sometime caching responses and sometime not caching them (all the responses have Cache-Control: max-age=600).
The test is simple: I did a test.php script that was just setting the headers and returning a simple JSON:
<?php
header('Content-Type: application/json');
header('Cache-Control: max-age=600');
?>
{
"result": {
"employeeId": "<?php echo $_GET['eId']; ?>",
"dateTime": "<?php echo date('Y-m-d H:i:s'); ?>'" }
}
This is the response I get from the PHP page:
HTTP/1.1 200 OK
Date: Thu, 28 Nov 2013 11:41:55 GMT
Server: Apache
X-Powered-By: PHP/5.3.17
Cache-Control: max-age=600
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/json
{
"result": {
"employeeId": "",
"dateTime": "2013-11-28 11:41:55'"
}
}
Then I've created a simple app and added AFNetworking library.
When I call the script with few parameters, the cache works properly:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *params = #{
#"oId": #"4011",
#"eId": self.firstTest ? #"1" : #"0",
#"status": #"2031",
};
[manager GET:#"http://www.mydomain.co.uk/test.php" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
NSLog(#"Cache current memory usage (after call): %d", [cache currentMemoryUsage]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
But when I increase the number of parameters, like:
NSDictionary *params = #{
#"organizationId": #"4011",
#"organizationId2": #"4012",
#"organizationId3": #"4013",
#"organizationId4": #"4014",
#"organizationId5": #"4015",
#"organizationId6": #"4016",
#"eId": self.firstTest ? #"1" : #"0",
#"status": #"2031",
};
it doesn't work anymore and it execute a new request each time it is called.
I've done many tests and it seems to me that it is related to the length of the URL, because if I includes this set of params:
NSDictionary *params = #{
#"oId": #"4011",
#"oId2": #"4012",
#"oId3": #"4013",
#"oId4": #"4014",
#"oId5": #"4015",
#"oId6": #"4016",
#"eId": self.firstTest ? #"1" : #"0",
#"status": #"2031",
};
It works!!
I've done many tests and that's the only pattern I've found...
To exclude AFNetworking from the equation, I've created another test program that uses NSURLConnection only and I can see the same behaviour so it's not AFNetworking and definitely NSURLCache. This is the other test:
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://www.mydomain.co.uk/test.php?eId=%#&organizationId=4011&organizationId2=4012&organizationId3=4013&organizationId4=4014&organizationId5=4015&organizationId6=4016", self.firstTest ? #"1" : #"0"]]; // doesn't work
//NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://www.mydomain.co.uk/test.php?eId=%#&oId=4011&oId2=4012&oId3=4013&oId4=4014&oId5=4015&oId6=4016", self.firstTest ? #"1" : #"0"]]; // work
//NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://www.mydomain.co.uk/test.php?eId=%#", self.firstTest ? #"1" : #"0"]]; // work
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if (error == nil) {
// Parse data here
NSString *responseDataStr = [NSString stringWithUTF8String:[data bytes]];
NSLog(#"Response data: %#", responseDataStr);
}
I've also tried to establish how many characters in the URL will trigger the problem but even in this case I've got strange results:
This one is 112 characters long and it doesn't work:
http://www.mydomain.co.uk/test.php?eId=1&organizationId=4011&organizationId2=4012&organizationId3=4013&orgaId4=4
This one is 111 characters long and it works:
http://www.mydomain.co.uk/test.php?eId=1&organizationId=4011&organizationId2=4012&organizationId3=4013&orgId4=4
Ive renamed the PHP script to see if the first part of the URL would matter and I've got a strange behaviour again:
This one is 106 characters long and it doesn't work:
http://www.mydomain.co.uk/t.php?eId=1&organizationId=4011&organizationId2=4012&organizationId3=4013&org=40
This one is 105 characters long and it works:
http://www.mydomain.co.uk/t.php?eId=1&organizationId=4011&organizationId2=4012&organizationId3=4013&org=4
So I've removed 3 characters from the page name and I've got a working threshold 6 characters lower.
Any suggestion?
Thanks,
Dem
I am witnessing something similar with certain responses not being cached by NSURLCache and I have come up with another possible reason:
In my case I have been able to ascertain that the responses not being cached are the ones that are returned using Chunked transfer-encoding. I've read elsewhere that NSURLCache should cache those after iOS 6 but for some reason it doesn't in my case (iOS 7.1 and 8.1).
I see that your example response shown here, also has the Transfer-Encoding: chunked header.
Could it be that some of your responses are returned with chunked encoding (those that are not cached) and some are not (those that are cached)?
My back-end is also running PHP on Apache and I still can't figure out why it does that...
Probably some Apache extension...
Anyway, I think it sounds more plausible than the request URL length scenario.
EDIT:
It's been a while, but I can finally confirm that in our case, it is the chunked transfer encoding that causes the response not to be cached. I have tested that with iOS 7.1, 8.1, 8.3 and 8.4.
Since I understand that it is not always easy to change that setting on your server, I have a solution to suggest, for people who are using AFNetworking 2 and subclassing AFHTTPSessionManager.
You could add your sub-class as an observer for AFNetworking's AFNetworkingTaskDidCompleteNotification, which contains all the things you will need to cache the responses yourself. That means: the session data task, the response object and the response data before it has been processed by the response serializer.
If your server uses chunked encoding for only a few of its responses, you could add code in -(void)didCompleteTask: to only cache responses selectively. So for example you could check for the transfer-encoding response header, or cache the response based on other criteria.
The example HTTPSessionManager sub-class below caches all responses that return any data:
MyHTTPSessionManager.h
#interface MyHTTPSessionManager : AFHTTPSessionManager
#end
MyHTTPSessionManager.m
#import "MyHTTPSessionManager.h"
#implementation MyHTTPSessionManager
+ (instancetype)sharedClient {
static MyHTTPClient *_sharedClient = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[[NSNotificationCenter defaultCenter] addObserver:_sharedClient selector:#selector(didCompleteTask:) name:AFNetworkingTaskDidCompleteNotification object:nil];
});
return _sharedClient;
}
- (void)didCompleteTask:(NSNotification *)notification {
NSURLSessionDataTask *task = notification.object;
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
NSData *responseData = notification.userInfo[AFNetworkingTaskDidCompleteResponseDataKey];
if (!responseData.length) {
// Do not cache empty responses.
// You could place additional checks above to cache responses selectively.
return;
}
NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:responseData];
[[NSURLCache sharedURLCache] storeCachedResponse:cachedResponse forRequest:task.currentRequest];
}
I tried to come up with some sort of cleaner solution, but it seems that AFNetworking does not provide a callback or a delegate method that returns everything we need early enough - that is, before it has been serialized by the response serializer.
Hope people will find this helpful :)
Did you try to configure
NSURLRequestCachePolicy
for NSURLRequest
+ (id)requestWithURL:(NSURL *)theURL cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeoutInterval
These constants are used to specify interaction with the cached responses.
enum
{
NSURLRequestUseProtocolCachePolicy = 0,
NSURLRequestReloadIgnoringLocalCacheData = 1,
NSURLRequestReloadIgnoringLocalAndRemoteCacheData =4,
NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,
NSURLRequestReturnCacheDataElseLoad = 2,
NSURLRequestReturnCacheDataDontLoad = 3,
NSURLRequestReloadRevalidatingCacheData = 5
};
typedef NSUInteger NSURLRequestCachePolicy;
You could investigate what your cached response is from the sharedURLCache by subclassing NSURLProtocol and overriding startLoading:
add in AppDelegate application:didFinishLaunchingWithOptions:
[NSURLProtocol registerClass:[CustomURLProtocol class]];
Then create a subclass of NSURLProtocol (CustomURLProtol) and override startLoading
- (void)startLoading
{
self.cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:self.request];
if (self.cachedResponse) {
[self.client URLProtocol:self
didReceiveResponse:[self.cachedResponse response]
cacheStoragePolicy:[self.cachedResponse storagePolicy]];
[self.client URLProtocol:self didLoadData:[self.cachedResponse data]];
}
[self.client URLProtocolDidFinishLoading:self];
}
self.cachedResponse is a property NSCachedURLResponse i've added. You can see if anything is wrong with any cachedResponse here.

POST request with AFNetworking 2.0 - AFHTTPSessionManager

Hej,
I am struggling with doing a POST request to the parse REST API. I am using AFNetworking 2.0. My code for the AFHTTPSessionManager Subclass looks as follows:
+ (ParseAPISession *)sharedSession {
static ParseAPISession *sharedSession = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedSession = [[ParseAPISession alloc] initWithBaseURL:[NSURL URLWithString:kSDFParseAPIBaseURLString]];
});
return sharedSession;
}
And:
- (id)initWithBaseURL:(NSURL *)url {
self = [super initWithBaseURL:url];
if (self) {
[self.requestSerializer setValue:kSDFParseAPIApplicationId forHTTPHeaderField:#"X-Parse-Application-Id"];
[self.requestSerializer setValue:kSDFParseAPIKey forHTTPHeaderField:#"X-Parse-REST-API-Key"];
}
return self;
}
I am doing the request like this:
[[ParseAPISession sharedSession] POST:#"ClassName" parameters: [NSDictionary dictionaryWithObjectsAndKeys:#"name", #"name", nil]
success:^(NSURLSessionDataTask *task, id abc) {
NSLog(#"%#", abc);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(#"%#", error);
}];
Doing this I always get this kind of error:
Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (JSON text did not start with array or object and option to allow fragments not set.) UserInfo=0x8c72420 {NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
Since the GET Request works like a charm I am quite confused why I can’t POST something. Can anybody halp me with this problem?
Best regards!
UPDATE
Happily after testing around a lot this Error message isn't displayed anymore, unfortuatelly another appeared:
<NSHTTPURLResponse: 0x8b96d40>
{ URL: https://api.parse.com/1/users }
{ status code: 400,
headers {
"Access-Control-Allow-Origin" = "*";
"Access-Control-Request-Method" = "*";
"Cache-Control" = "no-cache";
Connection = "keep-alive";
"Content-Length" = 130;
"Content-Type" = "application/json; charset=utf-8";
Date = "Wed, 30 Oct 2013 20:01:58 GMT";
Server = "nginx/1.4.2";
"Set-Cookie" = "_parse_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFRiIlNjIxZjUxMzY3NWVhZWJmMDYyYWYwMGJiZTQ3MThmMWE%3D--851bd31b07e7dba2c5f83bb13a8d801ecbea42c4; domain=.parse.com; path=/; expires=Fri, 29-Nov-2013 20:01:58 GMT; secure; HttpOnly";
Status = "400 Bad Request";
"X-Runtime" = "0.060910";
"X-UA-Compatible" = "IE=Edge,chrome=1";
} }
Can anyone tell me what the Status: 400 Bad Request is telling me and how I can get rid of it?
This error means that your POST request went through, the server is successfully returning you some data, which NSJSONSerialization is having trouble parsing.
You probably need to set your AFJSONResponseSerializer to allow JSON fragments.
In the init method of your AFHTTPSessionManager subclass:
AFJSONResponseSerializer *responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[self setResponseSerializer:responseSerializer];
If this doesn't work, you probably have an encoding issue. From the NSJSONSerialization class reference:
The data must be in one of the 5 supported encodings listed in the JSON specification: UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE. The data may or may not have a BOM. The most efficient encoding to use for parsing is UTF-8, so if you have a choice in encoding the data passed to this method, use UTF-8.
Check the encoding type sent by your server.
Finally, you can either set breakpoints inside of AFNetworking, or set up AFNetworkActivityLogger, which will log requests as they are sent and received to your console. This tool is incredibly helpful for debugging this type of issue.
This worked for me :
in the AFHTTPSessionManager subclass initialise it with the following serialisers:
[self setRequestSerializer:[AFHTTPRequestSerializer serializer]];
[self setResponseSerializer:[AFJSONResponseSerializer serializer]];

Make iPhone to send URLEncoded string instead of JSON

I have a Symfony2 server that receives HTTP POSTs from JQuery using:
var myJSON = {key1: "value1", key2: ["value2", "value3"]};
$.post(myURL, {myJSON}, function(json){}, "json");
This works perfect and internally converts the json in a Request object that, once in the Controller, I can get straightforward with $this->getRequest()->get('key1') or get('key2') obtaining some well formed PHP objects with no additional work.
So I have a complete application with JQuery and Symfony2 working this way.
Now I need to develop a mobile client using iPhone SDK and Objective C.
But all examples I am finding to do it send the JSON and convert it to PHP objects once in the server using json_decode. Those examples use this piece of code:
NSArray *myArray = [NSArray arrayWithObjects: #"Value2", #"Value3", nil];
NSDictionary *myDict = [NSDictionary dictionaryWithObjectsAndKeys: #"Value1", #"key1", myArray, #"Value2"];
NSData* requestData = [NSJSONSerialization dataWithJSONObject:myDict options:NSJSONWritingPrettyPrinted error:&error];
NSLog(#"JSON string:%#", [[NSString alloc] initWithData:requestData encoding:NSUTF8StringEncoding]); // To check that the conversion to JSON is indeed being performed perfectly!!
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"XMLHttpRequest" forHTTPHeaderField:#"X-Requested-With"];
[request setValue:[NSString stringWithFormat:#"%d", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: requestData];
This sends directly the JSON data to the server and the $this->getRequest()->get('key1') returns null. This approach expects to receive that JSON thata in the content body of the HTTP Request and do a PHP json_decode to manage the data.
Ok, I can get it modifying my "API" to check what kind of data is coming and json_decoding if it is JSON or the getRequest thing if it is URLEncode.
But before doing that workaround, isn't there an easy way to get a JQuery parallel conversion getting the linked NSDictionaries and NSArrays to be URLEncoded and sent to the server as application/x-www-form-urlencoded to get the data in the server always in the getRequest()->get('key1') style?
This works perfect and internally converts the json in a Request
object that, once in the Controller, I can get straightforward with
$this->getRequest()->get('key1') or get('key2') obtaining some well
formed PHP objects with no additional work.
Symfony does not internally convert your json in a Request object!
If you want one way for working with data you need to send data with only one type (json or x-www-url-encoded). I wrote you in the previous question that you can encode iOS to send data with x-www-url-encoded but you can also send JSON in jQuery.post and from iOS. And then you must implement only:
$data = json_decode($this->getRequest()->getContent());
To send JSON data in your JS you need next code:
$.ajax({
type: "POST",
url: myURL,
data: JSON.stringify(myJSON),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(json){},
});

Generate JSON object with transactionReceipt

I've been the past days trying to test my first in-app purchse iphone application. Unfortunately I can't find the way to talk to iTunes server to verify the transactionReceipt.
Because it's my first try with this technology I chose to verify the receipt directly from the iPhone instead using server support. But after trying to send the POST request with a JSON onbject created using the JSON api from google code, itunes always returns a strange response (instead the "status = 0" string I wait for).
Here's the code that I use to verify the receipt:
- (void)recordTransaction:(SKPaymentTransaction *)transaction {
NSString *receiptStr = [[NSString alloc] initWithData:transaction.transactionReceipt encoding:NSUTF8StringEncoding];
NSDictionary *jsonDictionary = [NSDictionary dictionaryWithObjectsAndKeys:#"algo mas",#"receipt-data",nil];
NSString *jsonString = [jsonDictionary JSONRepresentation];
NSLog(#"string to send: %#",jsonString);
NSLog(#"JSON Created");
urlData = [[NSMutableData data] retain];
//NSURL *sandboxStoreURL = [[NSURL alloc] initWithString:#"https://sandbox.itunes.apple.com/verifyReceipt"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"https://sandbox.itunes.apple.com/verifyReceipt"]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[jsonString dataUsingEncoding:NSUTF8StringEncoding]];
NSLog(#"will create connection");
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
maybe I'm forgetting something in the request's headers but I think that the problem is in the method I use to create the JSON object.
HEre's how the JSON object looks like before I add it to the HTTPBody :
string to send: {"receipt-data":"{\n\t\"signature\" = \"AUYMbhY
...........
D0gIjEuMCI7Cn0=\";\n\t\"pod\" = \"100\";\n\t\"signing-status\" = \"0\";\n}"}
The responses I've got:
complete response {
exception = "java.lang.IllegalArgumentException: Property list parsing failed while attempting to read unquoted string. No allowable characters were found. At line number: 1, column: 0.";
status = 21002;
}
Thanks a lot for your guidance.
I have just fixed that after 2 days of struggling. You have to encode receipt using Base64 before inserting into json object. Like that (Ruby):
dataForVerification = {"receipt-data" => Base64.encode64(receipt)}.to_json
Base64 is not mentioned anywhere in the official docs (at least for SDK 3.0), only on a couple of blogs.
For instance, here the guy encodes the receipt in Base64 before passing it to the PHP server, but does not decode it back in PHP, thus sending Base64-encoded string to iTunes.
Re: "21002: java.lang.IllegalArgumentException: propertyListFromString parsed an object, but there's still more text in the string.:"
I fixed a similar issue in my code by wrapping the receipt data in {} before encoding.
The resulting receipt looks like:
{
"signature" = "A[...]OSzQ==";
"purchase-info" = "ew[...]fQ==";
"pod" = "100";
"signing-status" = "0";
}
Here's the code I use:
receipt = "{%s}" % receipt // This step was not specified - trial and error
encoded = base64.b64encode(receipt)
fullpost = '{ "receipt-data" : "%s" }' % encoded
req = urllib2.Request(url, fullpost)
response = urllib2.urlopen(req)
Apple's Response:
{"receipt":{"item_id":"371235", "original_transaction_id":"1012307", "bvrs":"1.0", "product_id":"com.foo.cup", "purchase_date":"2010-05-25 21:05:36 Etc/GMT", "quantity":"1", "bid":"com.foo.messenger", "original_purchase_date":"2010-05-25 21:05:36 Etc/GMT", "transaction_id":"11237"}, "status":0}
Good luck!