Programmatically tap on HTML href in order to update app - iphone

I'm planning updates for an enterprise app with ad-hoc distribution.
For updates, Apple recommends having the user visit an HTML page and tap on a link:
href="itms-services://?action=download-manifest&url=http://example.com/
manifest.plist"
See http://help.apple.com/iosdeployment-apps/#app43ad871e
I don't want to do this. I want the app to programmatically check for updates on launch and alert the user with a UIAlertView that an update is available.
Here's what I have so far in application didFinishLaunching. The complicated plist parsing comes from the structure of an example plist found here: http://help.apple.com/iosdeployment-apps/#app43ad78b3
NSLog(#"checking for update");
NSData *plistData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://example.com/MyApp.plist"]];
if (plistData) {
NSLog(#"finished checking for update");
NSError *error;
NSPropertyListFormat format;
NSDictionary *plist = [NSPropertyListSerialization propertyListWithData:plistData options:NSPropertyListImmutable format:&format error:&error];
if (plist) {
NSArray *items = [plist valueForKey:#"items"];
NSDictionary *dictionary;
if ([items count] > 0) {
dictionary = [items objectAtIndex:0];
}
NSDictionary *metaData = [dictionary objectForKey:#"metadata"];
float currentVersion = [[[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"] floatValue];
float newVersion = [[metaData objectForKey:#"bundle-version"] floatValue];
NSLog(#"newVersion: %f, currentVersion: %f", newVersion, currentVersion);
if (newVersion > currentVersion) {
NSLog(#"A new update is available");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Update available" message:#"A new update is available." delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"UPDATE", nil];
[alert show];
}
}
}
Then I have my UIAlertView delegate method:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1) {
NSLog(#"downloading full update");
UIWebView *webView = [[UIWebView alloc] init];
[webView loadRequest:[[NSURLRequest alloc] initWithURL:[NSURL URLWithString:#"itms-services://?action=download-manifest&url=http://example.com/MyApp.plist"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0]];
}
}
A few things:
I know [alert show] shouldn't be called in application didFinish, but I'll change it later.
I don't know how quickly plistData will be downloaded and how this download affects the app.
More importantly, my alert view delegate method doesn't work, and the update doesn't download. Even when I introduce webView with #property (nonatomic, strong) UIWebView *webView, the method doesn't do anything.
I think Dropbox has the MIME configured properly because I can download the .ipa through google Chrome.
So what I really need is a way using NSURLConnection (NSURLRequest etc.) to replicate the act of a user tapping on an HTML href. After that I think the full update will occur.

You can open a URL automatically using
[[UIApplication sharedApplication] openURL:...];
I don't know if it works for itms-services: urls, but it works for other bespoke URL schemes like tel:, fb: etc. so it should do unless Apple have specifically blocked it.

Related

Error 204, The Request Did not Return any Content While Posting data to Twitter

I tried to post from twitter but it not posting the comments. It display an error 204 , in the facebook the same data is successfully posted but in the twitter i got an error can any one have an idea How to solve it
-(void)postDataOnTwitterMethod{
if ([[FHSTwitterEngine sharedEngine]isAuthorized]) {
NSData *dataFromPath = UIImageJPEGRepresentation(cameraImage,1.0);
number = (arc4random()%10000)+1; //Generates Number from 1 to 10000.
RndNo = [NSString stringWithFormat:#"%i", number];
NSLog(#" ITEM %#",RndNo);
NSString *avalabelDate = [NSString stringWithFormat:#"%#_%#",[CommonMethods getCurrentDateAndTime],self.AvailableTillTextField.text];
NSString *theWholeString = [NSString stringWithFormat:#"Item No: %#\nItemName: %#\nItemCost: %#\nAvailableTill: %#\nCategory: %#\nDescription: %#",RndNo,self.NameTextField.text,self.PriceTextField.text,avalabelDate,self.ListTypeTextField.text,self.DecTextView.text];
dispatch_async(GCDBackgroundThread, ^{
#autoreleasepool {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSError *returnCode = [[FHSTwitterEngine sharedEngine]postTweet:theWholeString withImageData:dataFromPath];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSString *title = nil;
NSString *message = nil;
if (returnCode) {
title = [NSString stringWithFormat:#"Error %d",returnCode.code];
message = returnCode.localizedDescription;
} else {
title = #"Tweet Posted";
}
dispatch_sync(GCDMainThread, ^{
#autoreleasepool {
UIAlertView *av = [[UIAlertView alloc]initWithTitle:title message:message delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[av show];
}
});
}
});
}
else{
[[FHSTwitterEngine sharedEngine]showOAuthLoginControllerFromViewController:self withCompletion:^(BOOL success) {
NSLog(success?#"L0L success":#"O noes!!! Loggen faylur!!!");
}];
}
}
Your comments made me smile.
I believe it's an HTML error. It means the data was received and understood but you shouldn't expect a return. In other words, it's void. At least that's what I can see with a quick look around your code and my minimal understanding of Twitter API.
Now i am able to send the String but cant able to send the Image using this method
NSError *returnCode = [[FHSTwitterEngine sharedEngine]postTweet:theWholeString withImageData:imageData];
FHSTwitterEngine has some known bugs, and the problem is now fixed, see below:
Getting error while posting image using FHSTwitterEngine
compress the existing image with this code and you will get images posted.
NSData *data = UIImageJPEGRepresentation(imageView.image, 0.6);

Objective-C Tested app on iPhone, updated data, data doesnt change

I just built my first app and now I started testing it on my phone. It looks great when I first launch the app after building it, the launch images appears and then my json data is loaded via NSURL and displays properly on the app. But when I close down the app, update the data via php and mysql and re open it the launch image does not appear and my app is not updated. Is it possible to have the app launch like it did when I first launched it, always have launch image and also get the new data?
Here is my code if it helps.
- (void)viewDidLoad
{
[super viewDidLoad];
[self loadJSON];
}
- (void)loadJSON
{
Reachability *networkReachability = [Reachability reachabilityForInternetConnection];
NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];
if (networkStatus == NotReachable) {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: #"Error" message: #"Connection Failed" delegate: self cancelButtonTitle:#"Refresh" otherButtonTitles:nil]; [alert show]; [alert release];
});
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *url = [NSURL URLWithString:#"http://url.com/GetData.php"];
NSData *data = [NSData dataWithContentsOfURL:url options:0 error:nil];
NSArray *array = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSArray *firstItemArray = array[0];
NSString *yesNoString = firstItemArray[0];
NSString *dateString = firstItemArray[1];
NSString *timeString = firstItemArray[2];
NSString *homeString = firstItemArray[3];
NSString *awayString = firstItemArray[4];
NSString *lastUpdatedString = firstItemArray[5];
dispatch_async(dispatch_get_main_queue(), ^{
self.YesOrNo.text = yesNoString;
self.date.text = [#"For " stringByAppendingString:dateString];
self.time.text = timeString;
self.home.text = homeString;
self.away.text = awayString;
self.lastUpdated.text = lastUpdatedString;
self.lastUpdatedText.text = #"Last Updated";
self.vs.text = #"vs";
});
});
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
[self loadJSON];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)dealloc {
[_YesOrNo release];
[_date release];
[_time release];
[_vs release];
[_home release];
[_away release];
[_lastUpdatedText release];
[_lastUpdated release];
[super dealloc];
}
#end
If someone can point me in the right direction, that would be great and appreciated, thanks.
When you hit the round home button when running an app, it just puts it into the background, where it continues to run in a type of catatonic state. When you tap its icon again, it just wakes up, and doesn't re-launch. If you'd like to have your app completely quit when the user hits the home button, use the info.plist option "UIApplicationExitsOnSuspend" also known as "Application does not run in background." Set this to YES in your info.plist, and you'll get a fresh start every time. You can access this by clicking on your project in Xcode in the Project Navigator mode, and select the "info" tab at the top middle.
As it is your first app, you should try reading about the various devices and os versions.
Read about various application states, also the methods that are present in the AppDelegateClass, that get called when the app enters into various states,try reading about them.
So what has happened in your case is the device that you are using is Multitasking one. So when you press the home button or the sleep button the game goes to background, and is not killed. So next time when you tap on the application icon on your device, it brings it back to the foreground and does not relaunch it hence your Viewdidload method won't be called and your changes won't get reflected.
So, now to terminate your app, you can go through this link
http://www.gottabemobile.com/2013/02/10/how-to-close-apps-on-iphone/
Hope this helps.

UIWebView loading

I want load the html data in webview. At the button click, it open the viewcontroller and load the html data in this viewcontroller (add web view in this view controller using Interface builder). When the html data not proper loading and i press the back button, at that time crash the app. i am not doing allocation & init webview in the coding. set IBOUTLET using Interface builder & bind it.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[connection release];
NSString *strResponce = [[NSString alloc] initWithData:jsonData_Info encoding:NSUTF8StringEncoding];
[jsonData_Info release];
NSError *error;
SBJSON *json = [[SBJSON new] autorelease];
self.jsonArray_Info=[json objectWithString:strResponce error:&error];
str_InfoDetail = [[self.jsonArray_Info objectAtIndex:0] valueForKey:#"Page"];
str_html = [NSString stringWithFormat:#"%#",str_InfoDetail];
NSString *temp;
temp = [NSString stringWithFormat:#"<html><head><style>body{background-color:transparent;}</style></head><body><span style='color:white'>%#</span></body></html>",str_html];
//web_Information = [[UIWebView alloc]init];
web_Information.backgroundColor=[UIColor clearColor];
web_Information.opaque= NO;
[web_Information loadHTMLString:temp baseURL:nil];
[act stopAnimating];
[strResponce release];
}
please give me any solution.
thanks.
Pls post some code and crash log if you need answers. By the look of it I think it may be because of implementation of UIWebView delegate in your class. I think when you navigate back you do not make the delegate nil which can cause the app to crash

NSURLRequest converting NSData to an array

I need to convert data received from the web via an array in a PHP script into an array that I can pull values out of. Here's my code!
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
//NSString *payloadAsString = [NSString stringWithUTF8String:[receivedData bytes]];
NSArray *payloadAsString = [NSKeyedUnarchiver unarchiveObjectWithData:receivedData];
[payloadAsString finishEncoding];
verified = [payloadAsString objectAtIndex:0];
NSLog(#"logging");
//NSString *no = [[NSString alloc] init stringWithCString:verified];
NSLog(#"%#", verified);
if([verified isEqualToString:#"admin"]){
NSLog(#"test admin");
[self performSelector:#selector(changeViewAdmin) withObject:nil afterDelay:0.05];
}
if([verified isEqualToString:#"user"]){
NSLog(#"test user");
[self performSelector:#selector(changeView) withObject:nil afterDelay:0.05];
}
if([verified isEqualToString:#"No"]){
NSLog(#"test no");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Invalid UserName/Password combination!"
delegate:self
cancelButtonTitle:#"Okay"
otherButtonTitles:nil];
[alert show];
[alert release];
}
[payloadAsString release];
//NSLog(#"%#", verified);
// INSERT GOOGLE MAPS URL REQUEST HERE
/*if(requestType == 1){
NSString* addressText = payloadAsString;
// URL encode the spaces
addressText = [addressText stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding];
NSString* urlText = [NSString stringWithFormat:#"http://maps.google.com/maps?q=%#", addressText];
// lets throw this text on the log so we can view the url in the event we have an issue
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlText]];
// */
//
//}
[connection release];
self.receivedData = nil;
}
Unfortunately, my console returns null and asks if I've put the -finishencoding method in. Question is, if that's correct, where would I do so?
PS: Another question, is if I'm retrieving an array of data from a database, is a PHP script the best way to go? Thank you.
1) Of all this code the only string relevant to your question is
NSArray *payloadAsString = [NSKeyedUnarchiver unarchiveObjectWithData:receivedData];
I really doubt that PHP script returns you data in NSKeyedUnarchiver-compatible format. I believe the only reason you don't get NSInvalidArgumentException exception from this method is that receivedData is nil (did you initialize it anywhere?). Try to make a string from what you receive like this
[[[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding] autorelease]
and log it. From this I hope it will be clear how to parse response.
2) Do not name NSArray instances like 'blahBlahString'. Strings and arrays are completely different.
NSKeyedUnarchiver can only unarchive instances which are produced by instances of the NSKeyedArchiver class.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSKeyedUnarchiver_Class/index.html

What should be the reason behind this leaky line?

I have follwowing peace of code in which I have specified the leaky line . As I am new to iPhone developement I can't understand what actually is wrong with that line . please have a look at that line and tell me .
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
//take away
//NSURL *url1 = [[NSURL alloc] initWithString:#"http://url/Service.asmx/takeAwayList"];
NSURL *url1 = [[NSURL alloc] initWithString:[NSString stringWithFormat:#"%#/Service.asmx/takeAwayList",serviceURL]];
NSMutableURLRequest* request1=[NSMutableURLRequest requestWithURL:url1];
[request1 setHTTPMethod:#"POST"];
[request1 setTimeoutInterval:10];
//*****the leaky line***********************///
NSData *data2=[[NSURLConnection sendSynchronousRequest:request1 returningResponse:nil error:nil] autorelease];
if(data2 == nil)
{
UIAlertView* alert = [[UIAlertView alloc]initWithTitle:#"Alert" message:#"The network is not available.\n Please check the Internet connection." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
else
{
NSXMLParser *xmlParser1 = [[NSXMLParser alloc] initWithData:data2];
//Initialize the delegate.
TakeAwayParser *takeAwayParser = [[TakeAwayParser alloc] initTakeAwayParser];
//Set delegate
[xmlParser1 setDelegate:takeAwayParser];
//Start parsing the XML file.
#try {
BOOL success = [xmlParser1 parse];
if(success)
NSLog(#"No Errors");
else
NSLog(#"Error Error Error!!!");
}
#catch (NSException * e) {
NSLog(#"Exception in parsing %# %#",[e name], [e reason]);
}
[takeAwayParser release];
[xmlParser1 release];
}
//[request1 release];
// [response1 release];
//
[url1 release];
// [data2 release];
//new arrivals
//[data2 release];
[pool release];
I had issues with this as well in my Large project. After working with an Apple engineer on trying to locate the leaks, he finally asked the main Apple dev team behind NSURLConnection. They basically said that there is an internal cache that is not clearable at all in NSURLConnection and it was a known issue.
So I set out looking for alternatives. I found ASIHTTPConnection (link below) which works off of CFNetwork. It is designed to be a drop-in replacement for NSURLConnection, plus a bunch of other awesome goodies like downloading to disk instead of memory, download resuming, progress bar callbacks etc..
I have used it in all my projects and have never had any issues or complaints. An, in answer to your question, this is how I got rid of those memory leaks.
http://allseeing-i.com/ASIHTTPRequest/
This line isn't leaking, you shouldn't even being autoreleasing it.
Do yourself a favor and read the Memory Management Guide in Apple's developer docs, commented out releases in your code do not bode well.
EDIT: Hrm I take that back your code is completely fine except for that one line. Are you sure that it's leaking? It's returning an object with a retain count of 0, so you autoreleasing it should be causing trouble because it already has a retain count of 0.