diff --git a/sky/shell/BUILD.gn b/sky/shell/BUILD.gn index 5ac0e0f5809d315ff915d254912bb72f059c97e3..2e15c0918199093a4197450c40cf93e0d9789e34 100644 --- a/sky/shell/BUILD.gn +++ b/sky/shell/BUILD.gn @@ -174,6 +174,7 @@ if (is_android) { source_set("ios_scaffolding") { sources = [ + "ios/document_watcher.m", "ios/main_ios.mm", "ios/sky_app_delegate.h", "ios/sky_app_delegate.mm", diff --git a/sky/shell/ios/document_watcher.h b/sky/shell/ios/document_watcher.h new file mode 100755 index 0000000000000000000000000000000000000000..6e871954fac6c924cc07458ad21b9aabf5f347ac --- /dev/null +++ b/sky/shell/ios/document_watcher.h @@ -0,0 +1,13 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NDEBUG +#import + +@interface DocumentWatcher : NSThread +- (instancetype)initWithDocumentPath:(NSString*)path callbackBlock:(void (^)(void))callbackBlock; +- (void)cancel; +@end + +#endif // !NDEBUG \ No newline at end of file diff --git a/sky/shell/ios/document_watcher.m b/sky/shell/ios/document_watcher.m new file mode 100755 index 0000000000000000000000000000000000000000..6cf1db2dd97acc34fd48398774267c740b2ca044 --- /dev/null +++ b/sky/shell/ios/document_watcher.m @@ -0,0 +1,100 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#ifndef NDEBUG +#import "document_watcher.h" + +@interface DocumentWatcher () + +@property(nonatomic, readonly) NSDate* lastModifiedDate; +@property (copy) void (^callbackBlock)(void); + +@end + +@implementation DocumentWatcher { + NSString* _documentPath; + NSTimer* _timer; + CFRunLoopRef _loop; +} + +@synthesize lastModifiedDate = _lastModifiedDate; + +- (instancetype)initWithDocumentPath:(NSString*)path callbackBlock:(void (^)(void))callbackBlock { + self = [super init]; + + if (self) { + _documentPath = path; + self.callbackBlock = callbackBlock; + + [self start]; + } + + return self; +} + +- (void)main { + [self onCheck:nil]; + _timer = [[NSTimer scheduledTimerWithTimeInterval:1.0 + target:self + selector:@selector(onCheck:) + userInfo:nil + repeats:YES] retain]; + while (!self.isCancelled) { + _loop = CFRunLoopGetCurrent(); + CFRunLoopRunInMode(kCFRunLoopDefaultMode, + [[NSDate distantFuture] timeIntervalSinceNow], YES); + } +} + +- (void)_setLastModifiedDate:(NSDate*)lastModifiedDate path:(NSString*)path { + if ([_lastModifiedDate isEqualToDate:lastModifiedDate]) { + return; + } + + [_lastModifiedDate release]; + _lastModifiedDate = [lastModifiedDate retain]; + + if (_lastModifiedDate == nil && lastModifiedDate == nil) { + return; + } + + dispatch_async(dispatch_get_main_queue(), self.callbackBlock); +} + +- (void)onCheck:(id)sender { + if (![[NSFileManager defaultManager] fileExistsAtPath:_documentPath]) { + return; + } + + NSError* error = nil; + NSDictionary* attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:_documentPath + error:&error]; + if (error != nil) { + NSLog(@"[DocumentWatcher onCheck]: error reading attributes for path %@: %@", _documentPath, error); + return; + } + + [self _setLastModifiedDate:attributes.fileModificationDate path:_documentPath]; +} + +- (void)cancel { + [_timer invalidate]; + [_timer release]; + _timer = nil; + + if (_loop) { + CFRunLoopWakeUp(_loop); + _loop = NULL; + } + + [super cancel]; +} + +- (void)dealloc { + [_documentPath release]; + [_lastModifiedDate release]; + [super dealloc]; +} + +@end +#endif // !NDEBUG \ No newline at end of file diff --git a/sky/shell/ios/sky_surface.mm b/sky/shell/ios/sky_surface.mm index b0d55dd5c0d2a515b2e8ced14a7bcfbbdaa3543b..1cd88ba988ee10e1152aadce25c536d96e99b41c 100644 --- a/sky/shell/ios/sky_surface.mm +++ b/sky/shell/ios/sky_surface.mm @@ -16,6 +16,10 @@ #include "sky/shell/shell.h" #include "sky/shell/ui_delegate.h" +#ifndef NDEBUG +#include "document_watcher.h" +#endif + static inline sky::EventType EventTypeFromUITouchPhase(UITouchPhase phase) { switch (phase) { case UITouchPhaseBegan: @@ -62,6 +66,10 @@ static sky::InputEventPtr BasicInputEventFromRecognizer( sky::SkyEnginePtr _sky_engine; scoped_ptr _shell_view; + +#ifndef NDEBUG + DocumentWatcher *_document_watcher; +#endif } -(instancetype) initWithShellView:(sky::shell::ShellView *) shellView { @@ -137,7 +145,24 @@ static sky::InputEventPtr BasicInputEventFromRecognizer( } - (NSString*)skyInitialBundleURL { - return [[NSBundle mainBundle] pathForResource:@"app" ofType:@"skyx"]; + NSString *skyxBundlePath = [[NSBundle mainBundle] pathForResource:@"app" ofType:@"skyx"]; +#ifndef NDEBUG + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + NSString *skyxDocsPath = [documentsDirectory stringByAppendingPathComponent:@"app.skyx"]; + + if ([fileManager fileExistsAtPath:skyxDocsPath] == NO) { + if ([fileManager copyItemAtPath:skyxBundlePath toPath:skyxDocsPath error:&error]) { + return skyxDocsPath; + } + NSLog(@"Error encountered copying app.skyx from the Bundle to the Documents directory. Dynamic reloading will not be possible. %@", error); + return skyxBundlePath; + } + return skyxDocsPath; +#endif + return skyxBundlePath; } - (void)connectToEngineAndLoad { @@ -146,6 +171,12 @@ static sky::InputEventPtr BasicInputEventFromRecognizer( NSString *endpoint = self.skyInitialBundleURL; if (endpoint.length > 0) { +#ifndef NDEBUG + _document_watcher = [[DocumentWatcher alloc] initWithDocumentPath:endpoint callbackBlock:^{ + mojo::String string(endpoint.UTF8String); + _sky_engine->RunFromBundle(string); + }]; +#endif // Load from bundle mojo::String string(endpoint.UTF8String); _sky_engine->RunFromBundle(string); @@ -165,6 +196,16 @@ static sky::InputEventPtr BasicInputEventFromRecognizer( self.platformView->SurfaceDestroyed(); } +#ifndef NDEBUG +- (void)didMoveToWindow { + if (self.window == nil) { + [_document_watcher cancel]; + [_document_watcher release]; + _document_watcher = nil; + } +} +#endif + #pragma mark - UIResponder overrides for raw touches - (void)dispatchTouches:(NSSet*)touches phase:(UITouchPhase)phase {