App crash on creating NSdictionary for Json in IOS - iphone

i am working on in app purchase app in which i want to verify purchase transaction receipt with my developer server along with other information like Device VendorID, software version , device name and product id wish to buy.
I am using NSDictionary to create Json but it crash when i try to add
NSMutableArray *MainOBJ = [NSMutableArray arrayWithObjects:IDdict,deviceData,kMyFeatureIdentifier,jsonObjectString,nil];
in which IDdict is device id string , deviceData is dictionary which content device information like name , software version and kMyFeatureIdentifier is product id NSstring wish to buy. and jsonObjectString is encoded transaction receipt string.
here is my code
- (void)verifyReceipt:(SKPaymentTransaction *)transaction {
//TODO
// currently working on JSON to send to server .
NSLog(#"In verifyReceipt method");
jsonObjectString = [self encode:(uint8_t*)transaction.transactionReceipt.bytes length:transaction.transactionReceipt.length];
// jsonObjectString=#"TESTING";
NSLog(#"Json Object encoded receipt is %#",jsonObjectString);
NSString *IDdict = [[NSString alloc ]initWithString:[UIDevice currentDevice].identifierForVendor.UUIDString]; // Device UDID
NSArray *objects = [NSArray arrayWithObjects:#"NULL",[[UIDevice currentDevice] model],[[UIDevice currentDevice] name],nil];
NSArray *keys = [NSArray arrayWithObjects:#"serial",#"constructor",#"name",nil];
NSDictionary *deviceData = [NSDictionary dictionaryWithObjects:objects forKeys:keys]; // Device information like name , device model , serial number
NSLog(#"Json question dict created");
//TODO: **It crash here**
NSMutableArray *MainOBJ = [NSMutableArray arrayWithObjects:IDdict,deviceData,kMyFeatureIdentifier,jsonObjectString,nil]; // purchased Item ID of previous item
NSMutableArray *MainKeys = [NSMutableArray arrayWithObjects:#"ID",#"device",#"video","#receiptData", nil];
NSMutableDictionary *MainDict = [NSMutableDictionary dictionaryWithObjects:MainOBJ forKeys:MainKeys]; // final string of data
NSLog(#"Json Main dict created");
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:MainDict options:NSJSONWritingPrettyPrinted error:&error];
NSString *resultAsString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"Purchase product Json string:\n%#", resultAsString);
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[[NSURL alloc] initWithString:#"http://xyz/dev.php/video/verifyReceipt"]];
[request setPostValue:resultAsString forKey:#"verify"];
[request setDidFinishSelector:#selector(requestDone:)];
[request setTimeOutSeconds:120];
[request setDelegate:self];
[request setNumberOfTimesToRetryOnTimeout:2];
[request setDownloadProgressDelegate:self];
request.showAccurateProgress = YES;
i got "NSLog(#"Json question dict created");" in my log after it crashes.
and my expected json format is like this
{
"ID" : "E6E95901-006B-4569-8D2B-FA29A0307F80",
"device" : {
"name" : "iPad Simulator",
"constructor" : "iPad Simulator",
"serial" : "NULL"
},
"video" : "com.amm.happyclip.4445Video",
"receiptData":"DSKLFKSGERPOKFLJGMZEKLEMSERLKEMZTRKGDGFLefklezkgem"
}
Screenshot of error
Any suggestion , help appreciated Thank you
Encoding method which return string and i just assign that string to "jsonObjectString"
- (NSString *)encode:(const uint8_t *)input length:(NSInteger)length {
static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
NSMutableData *data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t *output = (uint8_t *)data.mutableBytes;
for (NSInteger i = 0; i < length; i += 3) {
NSInteger value = 0;
for (NSInteger j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
NSInteger index = (i / 3) * 4;
output[index + 0] = table[(value >> 18) & 0x3F];
output[index + 1] = table[(value >> 12) & 0x3F];
output[index + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '=';
output[index + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
}

Maybe each object in MainOBJ is nil and if you create dictionary with nil object it crashes your app, or they are already released.
try to log objects from MainOBJ array.

Related

how to access Salesforce Attachment Body (base64 binary data) in ios?

I am working on iOS native app for getting attachments from salesforce.
I have to show the salesforce attachments in my iPhone app for particular object like Leads,Contacts etc. For that i am using Rest Api and got response body. But in response body there is url but i want binary data of attachment body.
Here is my code:
My rest api request
NSString *attachments=[NSString stringWithFormat:#"select Name,Body, ContentType from Attachment"];
SFRestRequest *request = [[SFRestAPI sharedInstance] requestForQuery:attachments];
[[SFRestAPI sharedInstance] send:request delegate:self];
I get response in body in following format:
{
Body = "/services/data/v23.0/sobjects/Attachment/00P90000004SRFlEAO/Body";
ContentType = "application/video";
Name = "Video.MOV";
attributes = {
type = Attachment;
url = "/services/data/v23.0/sobjects/Attachment/00P90000004SRFlEAO";
};
}
Using this code to download after get body url:
SFRestRequest* downloadRequest = [self requestForFileContents:#"/services/data/v23.0/sobjects/Attachment/00P90000004SRFlEAO/Body"];
- (SFRestRequest *) requestForFileContents:(NSString *) path {
NSMutableDictionary *params = [NSMutableDictionary dictionary];
SFRestRequest *request = [SFRestRequest requestWithMethod:SFRestMethodGET path:path queryParams:params];
request.parseResponse = NO;
return request;}
You have to make a GET request to the URL returned in the Body field to fetch the actual binary content.
Check this code:
id url = #"http://blogs.independent.co.uk/wp-content/uploads/2012/12/google-zip.jpg";
[self getImageBase64:url];
-( NSString *) AFBase64EncodedStringFromString: (NSData*) data
{
NSUInteger length = [data length];
NSMutableData *mutableData = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t *input = (uint8_t *)[data bytes];
uint8_t *output = (uint8_t *)[mutableData mutableBytes];
for (NSUInteger i = 0; i < length; i += 3) {
NSUInteger value = 0;
for (NSUInteger j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
static uint8_t const kAFBase64EncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
NSUInteger idx = (i / 3) * 4;
output[idx + 0] = kAFBase64EncodingTable[(value >> 18) & 0x3F];
output[idx + 1] = kAFBase64EncodingTable[(value >> 12) & 0x3F];
output[idx + 2] = (i + 1) < length ? kAFBase64EncodingTable[(value >> 6) & 0x3F] : '=';
output[idx + 3] = (i + 2) < length ? kAFBase64EncodingTable[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithData:mutableData encoding:NSASCIIStringEncoding];
}
-(NSString *) getImageBase64:(NSString *) url
{
NSURLRequest * imageUrlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
NSURLResponse * response=nil;
NSError * error =nil;
NSData * data = [NSURLConnection sendSynchronousRequest:imageUrlRequest returningResponse:&response error:&error];
if(error == nil)
{
return [self AFBase64EncodedStringFromString:data];
}
return nil;
}

MapKit - Make route line follow streets when map zoomed in

I wrote simple application which draws route between two locations on MapKit. I am using Google Map API. I used resources I found online and here's the code I am using to make request to Google:
_httpClient = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:#"http://maps.googleapis.com/"]];
[_httpClient registerHTTPOperationClass: [AFJSONRequestOperation class]];
[_httpClient setDefaultHeader:#"Accept" value:#"application/json"];
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
[parameters setObject:[NSString stringWithFormat:#"%f,%f", coordinate.latitude, coordinate.longitude] forKey:#"origin"];
[parameters setObject:[NSString stringWithFormat:#"%f,%f", endCoordinate.latitude, endCoordinate.longitude] forKey:#"destination"];
[parameters setObject:#"true" forKey:#"sensor"];
NSMutableURLRequest *request = [_httpClient requestWithMethod:#"GET" path: #"maps/api/directions/json" parameters:parameters];
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject){
NSInteger statusCode = operation.response.statusCode;
if (statusCode == 200)
{
NSLog(#"Success: %#", operation.responseString);
}
else
{
NSLog(#"Status code = %d", statusCode);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", operation.responseString);
}
];
[_httpClient enqueueHTTPRequestOperation:operation];
This works flawlessly. When I run this and try to show route between LA and Chicago, here's how it looks like:
BUT. When I zoom map to street level, here's how route looks like:
Does anyone know how can I achieve that route I am drawing follows streets when map is zoomed? I'd like route to show exact path through the streets. I don't know if some additional parameter needs to be added to my request to Google.
Any help or advice would be great. Many thanks in advance!
[edit #1: Adding request URL and response from Google]
My request URL after creating operation object from code above looks like this:
http://maps.googleapis.com/maps/api/directions/json?sensor=true&destination=34%2E052360,-118%2E243560&origin=41%2E903630,-87%2E629790
Just paste that URL to your browser and you will see the JSON data Google sends as the response which I get in my code also.
[edit #2: Parsing answer from Google and building the path]
- (void)parseResponse:(NSData *)response
{
NSDictionary *dictResponse = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingMutableContainers error:nil];
NSArray *routes = [dictResponse objectForKey:#"routes"];
NSDictionary *route = [routes lastObject];
if (route)
{
NSString *overviewPolyline = [[route objectForKey: #"overview_polyline"] objectForKey:#"points"];
_path = [self decodePolyLine:overviewPolyline];
}
}
- (NSMutableArray *)decodePolyLine:(NSString *)encodedStr
{
NSMutableString *encoded = [[NSMutableString alloc] initWithCapacity:[encodedStr length]];
[encoded appendString:encodedStr];
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\"
options:NSLiteralSearch
range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len)
{
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do
{
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do
{
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
CLLocation *location = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:location];
}
return array;
}
It looks like Google is not giving you all the points, or you are not looking at all the points. Actually, I'd expect polylines between placemarks, not only placemarks like you seem to have (with a straight line).
Check DirectionsStatus in the response to see if you are limited
Provide the json data that Google sends back.
I'm not so sure they use a radically different Mercator projection from the one used by Google.
I believe that the projection used by MapKit is different than that used by Google Maps.
MapKit uses Cylindrical Mercator, while Google uses a variant of the Mercator Projection.
Converting Between Coordinate Systems
Although you normally specify
points on the map using latitude and longitude values, there may be
times when you need to convert to and from other coordinate systems.
For example, you typically use map points when specifying the shape of
overlays.
Quoted from Apple:

Getting the error in JSON parsing in iphone

I am trying to pars the json data and display in table
My JSON data is like this
{"isError":false,"ErrorMessage":"","Result":{"Count":4,"Data":[{"ContentID":"127_30_1309793318065","ContentTypeID":1,"UserCaption":"Gandhinagar(Kanjurmarg)","UserComment":"central\n","DateRecorded":"\/Date(1309793318000+0530)\/","Data":"","ShareType":true,"Views":0,"PlayTime},{},{},{}];};isError = 0;}
I am prasing like this
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *loginStatus = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding];
NSLog(#"%#",loginStatus);
//this is for the getting the data from the server with help of JSON
NSString *json_string = [[NSString alloc] initWithData:webData encoding:NSUTF8StringEncoding];
NSDictionary *result = [json_string JSONValue];
/
//this for holding the Array value which come from the server
NSMutableArray *results = [[NSMutableArray alloc] init];
for (int index = 0; index<[reviewsvalues count]; index++)
{
NSMutableDictionary * value = [reviewsvalues objectAtIndex:index];
ReviewsResult * result = [[ReviewsResult alloc] init];
result.User_Caption = [value objectForKey:#"UserCaption"];
result.ContentType_Id = [value objectForKey:#"DateRecorded"];
result.Average_Rating = [value objectForKey:#"AverageRating"];
//OVER here MY APP GET CRASH
}
}
BUt it get crash and give error
[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance
The problem is simple.
reviewsvalues should be an NSDictionary and you should not be calling objectAtIndex: for the reviewsvalues.
Instead you should call valueForKey like
int count = [[reviewsvalues valueForKey:#"Count"] intValue];
NSArray *reviewsArray = [reviewsvalues valueForKey:#"Data"];
int count = [reviewsArray count];
cell.textLabel.text = [[reviewsArray objectAtIndex:indexPath.row] valueForKey:#"ContentID"];
Hope this helps you.
Please let me know if you want more help on this.
You set reviewsvalues = [result objectForKey:#"Result"];
Which means reviewsvalues is now an NSDictionary.
"Result" is a dictionary, not an array:
{"Count":4,"Data":[...]}
NSDictionary doesn't respond to -objectAtIndex:, that's one of NSArray's methods.
You need another step:
NSArray *reviewsArray = [reviewsvalues objectForKey:#"Data"];
and while you are at it, you can use fast enumeration.
for (NSDictionary *review in reviewsArray) {
ReviewsResult * result = [[ReviewsResult alloc] init];
result.User_Caption = [review objectForKey:#"UserCaption"];
result.ContentType_Id = [review objectForKey:#"DateRecorded"];
result.Average_Rating = [review objectForKey:#"AverageRating"];
}
Edit: also, you should know that you've not coded this very defensively. What happens if the data isn't exactly as it is in your example? what happens if a value is missing, like "Data", or "Result"?
Your app should be robust enough to not choke if something slightly unexpected happens.

Verifying a Receipt with the App Store

Retrieve the receipt data from the transaction’s transactionReceipt property and encode it using base64 encoding.
How can I encode NSData using base64 encoding? Please give the code for that.
EDIT
I did it. but now the response is
{exception = "java.lang.NullPointerException"; status = 21002;}
my recipt verification method is this
-(BOOL)verifyReceipt:(SKPaymentTransaction *)transaction
{
NSString *recieptString = [transaction.transactionReceipt base64EncodingWithLineLength:0];
NSLog(#"%#",recieptString);
ASIFormDataRequest *request = [[ASIFormDataRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"https://buy.itunes.apple.com/verifyReceipt"]]];
[request setPostValue:recieptString forKey:#"receipt-data"];
[request setPostValue:#"95140bdac98d47a2b15e8e5555f55d41" forKey:#"password"];
[request start];
NSDictionary* subsInfo = [[request responseString] JSONValue];
NSLog(#"%#",subsInfo);
return subscriptionEnabled;
}
Where
NSString *recieptString = [transaction.transactionReceipt base64EncodingWithLineLength:0];
returns me base64 encoded string.
I also tried
NSString *recieptString = [transaction.transactionReceipt base64EncodingWithLineLength:[transaction.transactionReceipt length]];
but response is same.
can any one of you let me know where I could be wrong.
Thanks-
+ (NSString*)base64forData:(NSData*)theData {
const uint8_t* input = (const uint8_t*)[theData bytes];
NSInteger length = [theData length];
static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t* output = (uint8_t*)data.mutableBytes;
NSInteger i;
for (i=0; i < length; i += 3) {
NSInteger value = 0;
NSInteger j;
for (j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
NSInteger theIndex = (i / 3) * 4;
output[theIndex + 0] = table[(value >> 18) & 0x3F];
output[theIndex + 1] = table[(value >> 12) & 0x3F];
output[theIndex + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '=';
output[theIndex + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '=';
}
return [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
}
You need to post your receipt to "https://sandbox.itunes.apple.com/verifyReceipt" while testing in the sandbox environment.

Image Sent via XML from iPhone to App Engine

I am trying to send a small image along with some XML information to App Engine from my iPhone app. I am having trouble with the image somewhere along the path. There is no error given and data is being transfered into a Blob entry in Datastore Viewer but the blob files on App Engine do not appear in Blob Viewer. I have a suspicion that the image is being messed up in one of my transforms in App Engine, or is not being stored as the correct type in App Engine. What do you think?
On the iPhone, here is the relevant section that encodes the image (using a standard base64Encoding function) and adds it to a GDataXMLElement, which then gets added to a GDataXMLDoc and sent with ASIHTTPRequest:
NSString *dataString = [self.data base64Encoding];
GDataXMLElement *tempXMLElement = [GDataXMLElement elementWithName:#"data" stringValue: dataString];
[imageElement addChild: tempXMLElement];
the ASIHTTPRequest part:
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL: url];
[request setDelegate: self];
[request addRequestHeader:#"User-Agent" value: [NSString stringWithFormat:#"MyApp:%#", version]];
[request addRequestHeader:#"Content-Type" value:#"text/xml"];
[request setShouldStreamPostDataFromDisk:YES];
[request appendPostDataFromFile: path];
[request start];
On App Engine in Python (most likely where a problem lies):
image_data_xml_element = image_xml_node.getElementsByTagName("data")[0]
image_data_base64_unicode = image_data_xml_element.firstChild.data
image_data_base64_ascii = image_data_unicode.encode("utf8")
image_data_string = binascii.a2b_base64(image_data_base64_ascii)
new_image.data = db.Blob(image_data_string)
Additionally I have tried:
image_data_xml_element = image_xml_node.getElementsByTagName("data")[0]
image_data_base64_unicode = image_data_xml_element.firstChild.data
image_data_string = base64.b64decode(image_data_base64_unicode)
new_image.data = db.Blob(image_data_string)
Edit: For completeness, here is the objective-c base64 library I am using - it doesn't look like what I expected:
static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- (NSString *)base64Encoding;{
if ([self length] == 0)
return #"";
char *characters = malloc((([self length] + 2) / 3) * 4);
if (characters == NULL)
return nil;
NSUInteger length = 0;
NSUInteger i = 0;
while (i < [self length]){
char buffer[3] = {0,0,0};
short bufferLength = 0;
while (bufferLength < 3 && i < [self length])
buffer[bufferLength++] = ((char *)[self bytes])[i++];
// Encode the bytes in the buffer to four characters, including padding "=" characters if necessary.
characters[length++] = encodingTable[(buffer[0] & 0xFC) >> 2];
characters[length++] = encodingTable[((buffer[0] & 0x03) << 4) | ((buffer[1] & 0xF0) >> 4)];
if (bufferLength > 1)
characters[length++] = encodingTable[((buffer[1] & 0x0F) << 2) | ((buffer[2] & 0xC0) >> 6)];
else characters[length++] = '=';
if (bufferLength > 2)
characters[length++] = encodingTable[buffer[2] & 0x3F];
else characters[length++] = '=';
}
return [[[NSString alloc] initWithBytesNoCopy:characters length:length encoding:NSASCIIStringEncoding freeWhenDone:YES] autorelease];
}
The Blob Viewer displays files uploaded with the Blobstore API, not those added to regular datastore entities in Blob Properties.
What I ended up doing was sending the image to the Blobstore prior to sending the XML then, if successful, send the XML including a key to the blobstore image data. I did not realize initially that Blobstore was a different entity than Blobs stored in the Datastore.
Thanks