diff --git a/iphone/Classes/TitaniumHost.m b/iphone/Classes/TitaniumHost.m index 236cfbd7e8f..de82ebfc751 100644 --- a/iphone/Classes/TitaniumHost.m +++ b/iphone/Classes/TitaniumHost.m @@ -626,6 +626,8 @@ - (void) endModules; { closingLock = [[NSLock alloc] init]; + [[NSUserDefaults standardUserDefaults] synchronize]; + for (id thisModule in [nativeModules objectEnumerator]) { if ([thisModule respondsToSelector:@selector(endModule)]) [thisModule endModule]; } @@ -637,6 +639,9 @@ - (void) endModules; [NSThread sleepForTimeInterval:0.25]; i++; } + VERBOSE_LOG(@"Modules closed, shutting down."); + + [[NSUserDefaults standardUserDefaults] synchronize]; [closingLock release]; closingLock = nil; diff --git a/iphone/Titanium.xcodeproj/project.pbxproj b/iphone/Titanium.xcodeproj/project.pbxproj index 20aa28b2aab..e0dd836c3b3 100755 --- a/iphone/Titanium.xcodeproj/project.pbxproj +++ b/iphone/Titanium.xcodeproj/project.pbxproj @@ -24,7 +24,6 @@ 241579C510C97FBB00E212F2 /* soapclient.js in Resources */ = {isa = PBXBuildFile; fileRef = 241579A210C97D5900E212F2 /* soapclient.js */; }; 241579EC10C9CFFB00E212F2 /* geo.html in Resources */ = {isa = PBXBuildFile; fileRef = 241579EB10C9CFFB00E212F2 /* geo.html */; }; 24157F9E10CADA9A00E212F2 /* fbvideo.html in Resources */ = {isa = PBXBuildFile; fileRef = 24157F9D10CADA9A00E212F2 /* fbvideo.html */; }; - 24157FCF10CADDAB00E212F2 /* blah.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = 24157FCE10CADDAB00E212F2 /* blah.mp4 */; }; 2415812510CAFA8700E212F2 /* movie.3gp in Resources */ = {isa = PBXBuildFile; fileRef = 2415812310CAFA8700E212F2 /* movie.3gp */; }; 2415812610CAFA8700E212F2 /* movie.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 2415812410CAFA8700E212F2 /* movie.jpg */; }; 241581A410CB06E800E212F2 /* xhr.html in Resources */ = {isa = PBXBuildFile; fileRef = 241581A310CB06E800E212F2 /* xhr.html */; }; @@ -422,7 +421,6 @@ 241579A210C97D5900E212F2 /* soapclient.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = soapclient.js; sourceTree = ""; }; 241579EB10C9CFFB00E212F2 /* geo.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = geo.html; sourceTree = ""; }; 24157F9D10CADA9A00E212F2 /* fbvideo.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = fbvideo.html; sourceTree = ""; }; - 24157FCE10CADDAB00E212F2 /* blah.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = blah.mp4; sourceTree = ""; }; 2415812310CAFA8700E212F2 /* movie.3gp */ = {isa = PBXFileReference; lastKnownFileType = file; path = movie.3gp; sourceTree = ""; }; 2415812410CAFA8700E212F2 /* movie.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = movie.jpg; sourceTree = ""; }; 241581A310CB06E800E212F2 /* xhr.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = xhr.html; sourceTree = ""; }; @@ -1116,7 +1114,6 @@ children = ( 2415812310CAFA8700E212F2 /* movie.3gp */, 2415812410CAFA8700E212F2 /* movie.jpg */, - 24157FCE10CADDAB00E212F2 /* blah.mp4 */, 241579A210C97D5900E212F2 /* soapclient.js */, 241579A010C97D5900E212F2 /* soap_header.html */, 241579A110C97D5900E212F2 /* soap.html */, @@ -1986,7 +1983,6 @@ 241579A410C97D5900E212F2 /* soap.html in Resources */, 241579EC10C9CFFB00E212F2 /* geo.html in Resources */, 24157F9E10CADA9A00E212F2 /* fbvideo.html in Resources */, - 24157FCF10CADDAB00E212F2 /* blah.mp4 in Resources */, 2415812510CAFA8700E212F2 /* movie.3gp in Resources */, 2415812610CAFA8700E212F2 /* movie.jpg in Resources */, 241581A410CB06E800E212F2 /* xhr.html in Resources */, diff --git a/iphone/modules/AnalyticsModule/AnalyticsModule.h b/iphone/modules/AnalyticsModule/AnalyticsModule.h index 87aea186789..8ac414708c0 100644 --- a/iphone/modules/AnalyticsModule/AnalyticsModule.h +++ b/iphone/modules/AnalyticsModule/AnalyticsModule.h @@ -20,6 +20,7 @@ NSTimer * timer; NSLock * mutex; + BOOL endingModule; BOOL disabled; } diff --git a/iphone/modules/AnalyticsModule/AnalyticsModule.m b/iphone/modules/AnalyticsModule/AnalyticsModule.m index 5a371f0318a..5ef7f2b5b68 100644 --- a/iphone/modules/AnalyticsModule/AnalyticsModule.m +++ b/iphone/modules/AnalyticsModule/AnalyticsModule.m @@ -24,28 +24,39 @@ @interface AnalyticsPacket : NSObject AnalyticsModule * module; NSMutableArray * eventArray; NSURLConnection * connection; + NSTimeInterval timeout; } +- (NSURLRequest *) urlRequest; +- (void)performAsynchronousData; +- (void)performSynchronousData; + @end @implementation AnalyticsPacket -- (id) initWithModule: (AnalyticsModule *) newModule sendEvents: (NSMutableArray *) newEventArray timeout: (NSTimeInterval) timeout; +- (id) initWithModule: (AnalyticsModule *) newModule sendEvents: (NSMutableArray *) newEventArray timeout: (NSTimeInterval) newTimeout; { self = [super init]; if(self == nil)return nil; - [[TitaniumHost sharedHost] pauseTermination]; - module = newModule; eventArray = newEventArray; + module = newModule; eventArray = newEventArray; timeout=newTimeout; if(AnalyticsModuleURL == nil){ AnalyticsModuleURL = [[NSURL URLWithString:@"https://api.appcelerator.net/p/v2/mobile-track"] retain]; } - NSMutableURLRequest * ourRequest = [NSMutableURLRequest requestWithURL:AnalyticsModuleURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:timeout]; - [ourRequest setHTTPMethod: @"POST"];[ourRequest setHTTPShouldHandleCookies:YES]; - [ourRequest setValue:@"text/json" forHTTPHeaderField:@"Content-Type"]; + + VERBOSE_LOG(@"[INFO] Analytics %@ will send %@",self,eventArray); + return self; +} +- (NSURLRequest *) urlRequest; +{ + NSMutableURLRequest * result = [NSMutableURLRequest requestWithURL:AnalyticsModuleURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:timeout]; + [result setHTTPMethod: @"POST"];[result setHTTPShouldHandleCookies:YES]; + [result setValue:@"text/json" forHTTPHeaderField:@"Content-Type"]; + NSMutableData * data = [[NSMutableData alloc] initWithData:[@"[" dataUsingEncoding:NSUTF8StringEncoding]]; BOOL firstItem = YES; - for (NSData *eventdata in newEventArray) + for (NSData *eventdata in eventArray) { if(firstItem){ firstItem = NO; @@ -55,19 +66,36 @@ - (id) initWithModule: (AnalyticsModule *) newModule sendEvents: (NSMutableArray [data appendData:eventdata]; } [data appendData:[@"]" dataUsingEncoding:NSUTF8StringEncoding]]; - [ourRequest setHTTPBody:data]; + [result setHTTPBody:data]; [data release]; + + return result; +} - connection = [[NSURLConnection alloc] initWithRequest:ourRequest delegate:self startImmediately:YES]; +- (void)performAsynchronousData; +{ + [[TitaniumHost sharedHost] pauseTermination]; + connection = [[NSURLConnection alloc] initWithRequest:[self urlRequest] delegate:self startImmediately:YES]; +} + +- (void)performSynchronousData; +{ + NSURLResponse * response = nil; + NSError * error = nil; - VERBOSE_LOG(@"[INFO] Analytics %@ will send %@",self,eventArray); - return self; + VERBOSE_LOG(@"[INFO] Analytics %@ will send synchronous",self); + + NSData * result = [NSURLConnection sendSynchronousRequest:[self urlRequest] returningResponse:&response error:&error]; + + VERBOSE_LOG(@"[INFO] Analytics %@ did synchronous:%@ response:%@ error:%@",self,result,response,error); } + - (void)connectionDidFinishLoading:(NSURLConnection *)URLConnection; { VERBOSE_LOG(@"[INFO] Analytics %@ successful!",self); [eventArray release]; + [[TitaniumHost sharedHost] resumeTermination]; [self autorelease]; } @@ -75,13 +103,13 @@ - (void)connection:(NSURLConnection *)URLConnection didFailWithError:(NSError *) { VERBOSE_LOG(@"[INFO] Analytics %@ failed with %@",self,error); [module keepEvents:eventArray]; + [[TitaniumHost sharedHost] resumeTermination]; [self autorelease]; } - (void) dealloc { VERBOSE_LOG(@"[INFO] Analytics %@ deallocing",self); - [[TitaniumHost sharedHost] resumeTermination]; [connection release]; [super dealloc]; } @@ -176,12 +204,14 @@ - (void)sendEvents; { if(events==nil || disabled)return; - if(packetDueDate==nil){ - packetDueDate = [[NSDate alloc] initWithTimeIntervalSinceNow:TI_ANALYTICS_TIMER_DELAY_IN_SEC]; - [self performSelector:@selector(sendEvents) withObject:nil afterDelay:TI_ANALYTICS_TIMER_DELAY_IN_SEC]; - return; - } else if ([packetDueDate timeIntervalSinceNow]>0){ - return; + if (!endingModule) { //If we're ending, it's ALL DUE. + if(packetDueDate==nil){ + packetDueDate = [[NSDate alloc] initWithTimeIntervalSinceNow:TI_ANALYTICS_TIMER_DELAY_IN_SEC]; + [self performSelector:@selector(sendEvents) withObject:nil afterDelay:TI_ANALYTICS_TIMER_DELAY_IN_SEC]; + return; + } else if ([packetDueDate timeIntervalSinceNow]>0){ + return; + } } if(connectionState == NetworkModuleConnectionStateUnknown){ @@ -190,16 +220,26 @@ - (void)sendEvents; //TODO: Refactor the network connection to be independant of things. } - if(connectionState == NetworkModuleConnectionStateNone)return; + if(connectionState == NetworkModuleConnectionStateNone){ + if(!endingModule) return; + //Else we should save this away for another time. + } [mutex lock]; if(events!=nil){ //Yes, we already checked before, but that was BEFORE the mutex! AnalyticsPacket * packet = [[AnalyticsPacket alloc] initWithModule:self sendEvents:events timeout:TI_ANALYTICS_NETWORK_TIMEOUT_IN_SEC]; if(packet != nil){ - [[TitaniumHost sharedHost] resumeTermination]; + if(endingModule){ + [packet performSynchronousData]; + } else { + [packet performAsynchronousData]; + } + [[TitaniumHost sharedHost] resumeTermination]; events=nil; //Releasing is handled through sleight of hand. [packetDueDate release];packetDueDate=nil; + } else if(endingModule) { + //Failed to make packet. Panic or save away? } else { [self performSelector:@selector(sendEvents) withObject:nil afterDelay:TI_ANALYTICS_TIMER_DELAY_IN_SEC]; } @@ -232,7 +272,9 @@ - (void)enqueuePlatformEvent:(NSString*)eventtype evtname:(NSString*)eventname d if(events==nil){ [[TitaniumHost sharedHost] pauseTermination]; events = [[NSMutableArray alloc] initWithObjects:newEvent,nil]; - [self performSelectorOnMainThread:@selector(sendEvents) withObject:nil waitUntilDone:NO]; + if (!endingModule) { + [self performSelectorOnMainThread:@selector(sendEvents) withObject:nil waitUntilDone:NO]; + } } else { [events addObject:newEvent]; } @@ -455,15 +497,34 @@ - (BOOL) startModule return YES; } +- (void) testConnection; +{ + NSURL * analyticsEchoUrl = [NSURL URLWithString:@"https://api.appcelerator.net/p/v1/echo"]; + + NSMutableURLRequest * ourRequest = [NSMutableURLRequest requestWithURL:analyticsEchoUrl cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:300]; + NSURLResponse * response = nil; + NSError * error = nil; + + NSData * result = [NSURLConnection sendSynchronousRequest:ourRequest returningResponse:&response error:&error]; + + VERBOSE_LOG(@"[INFO] Analytics forced a request:%@ response:%@ error:%@",result,response,error); +} + + + - (BOOL) endModule; { if (disabled) return YES; // first add to our queue (so we can flush) - [packetDueDate release]; - packetDueDate = [[NSDate alloc] init]; + endingModule = YES; + [self enqueuePlatformEvent:@"ti.end" evtname:@"ti.end" data:nil]; [self sendEvents]; + +// [self testConnection]; + + return YES; } @end diff --git a/iphone/modules/AppModule/AppModule.m b/iphone/modules/AppModule/AppModule.m index ae46fd67b4d..289ae3a5cb1 100644 --- a/iphone/modules/AppModule/AppModule.m +++ b/iphone/modules/AppModule/AppModule.m @@ -153,7 +153,6 @@ - (BOOL) startModule; - (BOOL) endModule; { - [[NSUserDefaults standardUserDefaults] synchronize]; return YES; }