Hi here is my code for sending private message to twitter follower/followings,message has been sent but problem is followers are getting message string with %20
-(void)PostOnTwitter :(NSArray *)ParamArray
{
NSLog(#"ParamArray===%#",ParamArray);
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter])
{
if(!accountStore)
accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
[accountStore requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error)
{
if(granted!=0)
{
NSArray *twitterAccounts = [self.accountStore accountsWithAccountType:accountType];
NSURL *MsgUrl=[NSURL URLWithString:#"https://api.twitter.com/1.1/direct_messages/new.json"];
NSDictionary *Msgparams = #{#"screen_name" : [ParamArray objectAtIndex:0], #"text" :
[[ParamArray objectAtIndex:1]stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] };
SLRequest *Msgrequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodPOST URL:MsgUrl parameters:Msgparams];
[Msgrequest setAccount:[twitterAccounts lastObject]];
[Msgrequest performRequestWithHandler:^(NSData *responseData,NSHTTPURLResponse *urlResponse,NSError *error) {
if (responseData) {
if (urlResponse.statusCode >= 200 && urlResponse.statusCode < 300) {
NSError *jsonError;
NSDictionary *timelineData = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:&jsonError];
if (timelineData) {
[self performSelectorOnMainThread:#selector(CardHasSent) withObject:nil waitUntilDone:NO];
}
}
}
}];
}
}];
}
}
My followers are getting private message like
user%20has%20sent%20you%20a%20card%20from%20happy%20heART%20cards.%20http://www.happyheartcards.net/o.php?t=ODYw
How can I send proper text?Please help.
I think probelm is stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding,but if I don't use NSUTF8StringEncoding message sending fails.
ParamArray has not been encoded earlier ParamArray===(
jry088,
"user has sent you a card from happy heART cards. http://www.happyheartcards.net/o.php?t=OTA1"
)
%20 is indeed the string escape for a space character, and this is the correct behaviour that you are requesting in using stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding. However, the Twitter API does want POST data for direct messages encoded like this:
https://dev.twitter.com/docs/api/1.1/post/direct_messages/new
I thought the most likely thing therefore was that you were running the encoding twice, which would mean that your % in %20s are getting re-encoded to say "Hey, I really mean a percentage sign here.
When I look at the code, there are multiple redundant calls to [ParamArray objectAtIndex:1] and earlier re-encoding of the string data into UTF8:
NSString *StringData = [ParamArray objectAtIndex:1];
const char *cString = [StringData UTF8String];
NSString *Datastringone = [NSString stringWithFormat:#"%s",cString];
NSString *str = [ParamArray objectAtIndex:1];
None of these variables or this processing ever gets used. This made me wonder whether the string in the ParamArray has already been encoded into UTF8 in an earlier part of your application, so that you are encoding it for the second time when you pass it in here.
NSDictionary *Msgparams = #{#"screen_name" : [ParamArray objectAtIndex:0], #"text" :
[[ParamArray objectAtIndex:1]stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] };
EDIT
Actually, I'm going to return to what I originally posted, before I updated the above. I think you're actually getting exactly what you ask for with that encoded text, and the question shouldn't be why you're getting %20s in your text, but rather why the code you've got now is accepting a DM whereas it was failing after all.
If you look at the API reference I linked above (https://dev.twitter.com/docs/api/1.1/post/direct_messages/new) it shows the POST data as % encoded earlier on, but if you actually look at the full code example of what is to be submitted, the string isn't actually encoded at all:
94 "text": "hello, tworld. welcome to 1.1."
So first—change as little else as possible, but remove the encoding stage, and confirm that you still can't send a DM. It could be that you fixed something else without realising it and that is why the POST started working. This would obviously be helped by not embedding the encoding stage into the creation of the dictionary. You get much more readable code if you create all the values separately and then pass the final encoded and prepared variables in when you create the dictionary. A few more temporary variables or pointers may be created but that's well worth it for the increased readability of the code. :)
Related
I'm using JSONHTTPClient library from github in my Objective c application. I have a lot of calls to my api and all works, but when I try add a POST function with headers and body, I get an error:
Error Domain=JSONModelErrorDomain Code=2 "Bad network response.
Probably the JSON URL is unreachable."
UserInfo={NSLocalizedDescription=Bad network response. Probably the
JSON URL is unreachable.}
I use the JSONFromURLWithString url to do a POST call. The api call works correctly, returning the data from server (I'm tested this from postman) But from this function in my objective c application I'm getting always error, why not get the response?
Am I sendind any data in bad format?
This is my code:
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:#"var1", #"keyVar1", #"5" , #"keyvar2", nil];//Here initialize my headers values into a dictionary
NSDictionary *dicty = [NSDictionary dictionaryWithObjectsAndKeys:#"6234", #"id", #"4324" , #"id2", nil];//This is my body
NSData *jsonDatass = [NSJSONSerialization dataWithJSONObject:dicty options:0 error:nil];//Here convert my body to nsdata
[JSONHTTPClient JSONFromURLWithString:#"myURL" method:#"POST" params:nil orBodyData:jsonData headers:parameters completion:^(id json, JSONModelError *err){
NSLog(#"have error?: %#", err);
NSLog(#"have response?: %#", json);
}];
I think for pass json in url first you need to convert json in to the string and then pass then string as a argument. Thats why in postman it works well.
I want to know the complete URL after you joining together,in the
[JSONHTTPClient JSONFromURLWithString:#"myURL" method:#"POST" params:nil
orBodyData:jsonData headers:parameters completion:^(id json, JSONModelError *err){
}
method,your complete URL shoud be same as
******************************** divider ***********************************
NSString *myString = [[NSString alloc] initWithData:jsonDatass encoding:NSUTF8StringEncoding];
myString = [myString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *uploadUrl = [NSString stringWithFormat:#"<YOU host URL>"?data=%#",myString];
also parameters Should be converted to string to splice into the url.
Please see code below:
+ (void)splashDataFromJSON:(NSData *)objectNotation error:(NSError **)error
{
NSError *localError = nil;
NSDictionary *parsedObject = [NSJSONSerialization JSONObjectWithData:objectNotation options:0 error:&localError];
if (localError != nil) {
*error = localError;
}
NSMutableArray* btms = [[NSMutableArray alloc] init];
NSMutableDictionary* btmManufacturerResolutionDictionary = [[BTMCache sharedManager] btmManufacturerResolutionDictionary];
NSArray *results = [parsedObject valueForKey:#"results"];
NSLog(#"Count %d", parsedObject.count);
NSString* imageBaseUrl = [[parsedObject valueForKey:#"general"] valueForKey:#"image_base_url"];
imageBaseUrl = [imageBaseUrl stringByAppendingString:#"hdpi/"];
NSString* splashImageName = [[[parsedObject valueForKey:#"general"] valueForKey:#"splash"] valueForKey:#"img"];
NSString* splashAdvertiserURL = [[[[parsedObject valueForKey:#"general"] valueForKey:#"splash"] valueForKey:#"url"] copy];
NSMutableString* appendedString = [[NSMutableString alloc] init];
for(int i =0 ;i<[splashAdvertiserURL length]; i++) {
char character = [splashAdvertiserURL characterAtIndex:i];
printf(&character);
sleep(0.1);
if (character != "!")
{
[appendedString appendFormat:#"%c", character];
}
}
[[SplashData sharedManager] setSplashAdvertiserURL:appendedString];
[[SplashData sharedManager] setSplashImageName:splashImageName];
splashAdvertiserURL = [[SplashData sharedManager] splashAdvertiserURL];
}
The point of interest is in splashAdvertiserURL. When I receive this data and print it out using po, it comes out as "https://radar.com/ref/go/84/". This is fine and what was expected. When I look at the incoming data in JSONLint it looks like this:
"general": {
"image_base_url": "https:\/\/radar.com\/img\/manufacturers\/",
"splash": {
"img": "image1.png",
"url": "https:\/\/radar.com\/ref\/go\/84\/"
}
},
As you can see, further on I put the NSString into a singleton with an NSString property. Nothing abnormal here. I then proceed to retrieve it to see that all is ok. Further to this the program continues. In another class I wish to retrieve this information, and when I try and do that, it throws EXC_BAD_ACCESS. There appears to be garbage in there.
I then put in a loop in the code as you can see to print out the characters one at a time. Very curiously, when I print that out using po I get:
https://
r
a
d
ar.com/ref/go/8 4!/"
Exactly in that format. If I then proceed to hardcode the string https://radar.com/ref/go/84/ - including escape characters and everything, then all works fine. No issues. If I handle a normal string incoming without escape characters it stores fine in the singleton as well, no issue. enter code here
I am pretty stumped here as to what is going on. Can someone assist?
Thank you
For URL you received as string you need to encode before use it to in your app. Have a look at below code:
NSString *sampleUrl = #"https:\/\/radar.com\/ref\/go\/84\/";
NSString *encodedUrl = [sampleUrl stringByAddingPercentEscapesUsingEncoding:
NSUTF8StringEncoding];
I like to call the json web service through my iphone app.
I try to pass the array like as follow:
NSArray *keys = [NSArray arrayWithObjects:#"key",nil];
NSArray *objects = [NSArray arrayWithObjects:venueId,nil];
NSDictionary *jsonDictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
NSString* jsonString = [jsonDictionary JSONRepresentation];
NSLog(#"%#",jsonString);
Call to webservice
SBJSON *json = [SBJSON new];
json.humanReadable = YES;
responseData = [[NSMutableData data] retain];
NSString *service = #"/DerializeDataTable";
NSString *requestString = [NSString stringWithFormat:#"{\"n\":\"%#\"}",jsonString];
NSLog(#"request string:%#",requestString);
Requsted String
{"n":"{"key":["4e78b7f7483bc8fe83ed2bf9","4de248a21520b8ceaabd9197","4f0d502be4b0dd89303e6bde","4f2a79a1e4b0b052a3f37633","500ebf52e4b0edbb8dbc7e9c","4d63a047a45b5481c872032d"]}"}
But can't able to get the response.
I don't know what is the reason.
I don't know the any problem on my side or server side.
You haven't posted the code where you actually send the request off to your web service, so it is going to be hard to help you.
The first thing you should do is isolate whether the problem is with your client (the app) or your server. You can do this by logging the response you get when you send the message - it sounds as if you're getting no response, in which case you might be better off examining your server logs to see if the request ever reaches your server. You might find it useful to use a proxy to actually see the network traffic as it leaves your app.
Looks like you have extra quotes in there. I think you mean:
{"n":{"key": ["4e78b7f7483bc8fe83ed2bf9","4de248a21520b8ceaabd9197","4f0d502be4b0dd89303e6bde","4f2a79a1e4b0b052a3f37633","500ebf52e4b0edbb8dbc7e9c","4d63a047a45b5481c872032d"]}}
Here are my method's to use RNCryptor to encrypt/decrypt a JSON string that I am sending to the web service. I am using a static IV variable which may be bad practice but please don't focus on that. Here is how I'm doing it:
Note: I'm using Matt Gallagher's NSData+Base64 category found here (at bottom of page)
-(NSString*)encryptString:(NSString*)plaintext withKey:(NSString*)key error:(NSError**)error{
NSData *data = [plaintext dataUsingEncoding:NSUTF8StringEncoding];
NSData *encryptionKey = [NSData dataFromBase64String:key];
NSData *IV = [NSData dataFromBase64String:ENCRYPTION_IV];
RNCryptorEngine *engine = [[RNCryptorEngine alloc] initWithOperation:kCCEncrypt settings:kRNCryptorAES256Settings key:encryptionKey IV:IV error:error];
[engine addData:data error:error];
NSData *encryptedData = [engine finishWithError:error];
NSString *based64Encrypted = [encryptedData base64EncodedString];
NSLog(#"Encrytped: %#", based64Encrypted);
return based64Encrypted;
}
-(NSString*) decryptString:(NSString*)cipherText withKey:(NSString*)key error:(NSError**)error;{
NSData *data = [NSData dataFromBase64String:cipherText];
NSData *encryptionKey = [NSData dataFromBase64String:key];
NSData *IV = [NSData dataFromBase64String:ENCRYPTION_IV];
RNCryptorEngine *engine = [[RNCryptorEngine alloc] initWithOperation:kCCDecrypt settings:kRNCryptorAES256Settings key:encryptionKey IV:IV error:error];
[engine addData:data error:error];
NSData *decryptedData = [engine finishWithError:error];
NSString *decryptedString = [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding];
NSLog(#"Decrypted: %#", decryptedString);
return decryptedString;
}
When I use a string like hello world it works fine. When I use a string like {"username":"developer","password":"abcdefG*12"} I imagine it hase something to do with the encoding but I really know what to use.
when I encrypt that string I get a base64 string and when I try to decrypt that I get an empty string.
UPDATE
It looks like it's failing because of the : in the json string.
What's weirder is it only fails with the string is in json format, I thought it was the : cause I tried that first but upon further investigation if I broke any of the JSON requirements ,'s {'s }'s it stopped working. It works with the RNEncryptor however so I'm not sure what I'm doing wrong. Either way, I think we may redesign the current flow
UPDATE 2
Here is where I am calling these methods:
NSDictionary *credentials = #{#"username":#"developer",#"password":#"abcdefG*12"};
NSString *jsonString = [ credentials JSONStringWithOptions:JKSerializeOptionNone error:&error];
NSLog(#"json string: %#", jsonString); //OUTPUTS: {"username":"developer","password":"abcdefG*12"}
CCGEncryption *encryptionObject = [[CCGEncryption alloc] init]; //THIS IS THE OBJECT WHERE THE encrypt/decrypt methods are
NSString *encrypted = [encryptionObject encryptString:jsonString withKey:ENCRYPTION_KEY error:&error];
if(error){
NSLog(#"Error:%#", error); //NO ERROR
}
NSString *decrypted = [encryptionObject decryptString:encrypted withKey:ENCRYPTION_KEY error:&error];
if(error){
NSLog(#"Error:%#", error); //NO ERROR
}
NSLog(#"decrypted: %#", decrypted); //OUTPUT: decrypted:
You're not collecting the data returned by addData:. The engine encrypts/decrypts as you go so that you don't have to hold the entire plaintext and ciphertext in memory. It doesn't accumulate the data unless it has to (for padding reasons). I suspect that the tests that are working are of different lengths than the ones that aren't.
You are correct that using a fixed IV is bad practice. If you use the same IV and key in multiple messages, then it is possible for attackers to recover parts of your messages by comparing the ciphertexts. If you are using AES-CBC without a random IV and an HMAC, then your AES is insecure in several ways. That is the problem RNCryptor was built to address and why the data format looks the way it does.
#jbtule is correct that I didn't particularly mean for people to use the engine directly and haven't heavily documented it, but there's no problem using it, and I can document it better to support that. That said, the engine itself is insanely simple; I just created it as a way to share code between the encryptor and decryptor. There's not much reason to use RNCryptor if you're going to bypass most of the security it provides. For the above code, it'd be a lot simpler to just call the one-shot CCCrypt().
i am very new to something called JSON Parsing in iOS. Can anybody explain me how to parse data from the scratch. Basically what I am tying to tell is that I am using Yahoo weather api for fetching the weather of a location.http://weather.yahooapis.com/forecastjson?w=2502265 is the link that I am using it .Now how can I parse the data from it?
I am getting error by doing this.Can somebody rectify it or tell me how to do it?
NSString * address = #"http://weather.yahooapis.com/forecastjson?w=2502265";
NSString * request = [NSString stringWithFormat:#"%#",address];
NSURL * URL = [NSURL URLWithString:request];
NSString* JSON = [NSString stringWithContentsOfURL:URL encoding:NSUTF8StringEncoding error:&error];
NSError *e = nil;
NSMutableArray *json = [NSJSONSerialization JSONObjectWithData:JSON options:NSJSONReadingMutableContainers error:&e];
NSLog(#"%#", json);
I have found that AFNetworking has made my life much easier.
I usually do something more than this like pass in POST parameters, but this will do for your case:
NSURL *url = [NSURL URLWithString:#"http://weather.yahooapis.com/forecastjson?w=2502265"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
// PARSE YOUR JSON DICTIONARY HERE
[self parseResult:JSON];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Failed to get data from web service, error: %#", [error localizedDescription]);
}];
[operation start];
// method to parse web service JSON
-(void)parseResult:(id)jsonDictionary
{
// parse result here
NSLog(#"Title = %#", [jsonDictionary valueForKey:#"title"];
}
Hope that helps.
Some basic info for you
What you're doing is requesting information from a web service.
You can think of web service like scripts on the server listening for specific POST or GET parameters.
You might have a web service like this:
http://www.mywebservice.com/rest/datatype=User?name=JohnSmith&age=20
Notice the "datatype", "name" and "age" are the parameters the web service is expecting. When you make a request to the web service, you usually pass in the value (in this case, "User", "JohnSmith" and "20" are the values) to those parameters.
These days, a web service will usually return you the data in the form of JSON or XML.
JSON doesn't have to do all those XML formatting, and as a result, JSON will tend to be more of the preferred choice for returning data.
The JSON data returned will look something like:
{
users = {(
({
name = John Smith;
age = 20;
address = 123 Easy Street EARTH
}),
({
name = Bob Brown;
age = 35;
address = 456 Some Road EARTH
})
)};
}
The above can be a bit intimidating at first but once you deal with it once, you'll realise that these are usually dictionaries nested inside arrays, nested inside giant dictionary.
As in the above case, the returned JSON data is a single giant dictionary containing all users. When you do something like:
[JSON objectForKey:#"users"]
You get the "users" array:
users = {(
({
name = John Smith;
age = 20;
address = 123 Easy Street EARTH
}),
({
name = Bob Brown;
age = 35;
address = 456 Some Road EARTH
})
)};
Then when you want to get a specific user from the "users" array, say Bob Brown, you would do something like:
[[JSON objectForKey:#"users"] objectAtIndex:1]
And that will return you:
{
name = Bob Brown;
age = 35;
address = 456 Some Road EARTH
}
Finally, to get a property of a user such as their name, you can go:
[[[JSON objectForKey:#"users"] objectAtIndex:1] valueForKey:#"name"];
For example:
NSLog(#"User name = %#", [[[JSON objectForKey:#"users"] objectAtIndex:1] valueForKey:#"name"]);
Real web service dictionaries usually aren't that nicely formatted, they're usually a bit more convoluted, especially those CMS like Drupal (run!!!) :D