├── .gitignore ├── pause.png ├── play.png ├── InjectionDemo ├── InjectionDemo │ ├── en.lproj │ │ ├── InfoPlist.strings │ │ └── INViewController.xib │ ├── Icon.png │ ├── INViewController.h │ ├── INRoseView.h │ ├── InjectionDemo-Prefix.pch │ ├── INAppDelegate.h │ ├── main.m │ ├── INViewController.m │ ├── InjectionDemo-Info.plist │ ├── INAppDelegate.m │ └── INRoseView.m ├── InjectionDemo.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── project.pbxproj └── InjectionDemo.approj │ ├── targets │ └── InjectionDemo │ │ ├── Release.generated │ │ ├── Release.final │ │ └── Release.overrides.json │ └── configuration.json ├── ApportablePlugin.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── ApportablePlugin.xccheckout └── project.pbxproj ├── Classes ├── APDebugController.h ├── APTextView.h ├── APLogController.h ├── APPluginMenuController.h ├── APLiveCoding.h ├── APConsoleController.h ├── APTextView.m ├── APDebugController.m ├── APLogController.m ├── APDebugController.xib ├── APPluginMenuController.xib ├── APLiveCoding.m ├── APConsoleWindow.xib ├── APPluginMenuController.m ├── APLogWindow.xib └── APConsoleController.m ├── prepare.py ├── Info.plist ├── README.md └── inject.py /.gitignore: -------------------------------------------------------------------------------- 1 | *xcuserdata* 2 | -------------------------------------------------------------------------------- /pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnno1962/ApportablePlugin/HEAD/pause.png -------------------------------------------------------------------------------- /play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnno1962/ApportablePlugin/HEAD/play.png -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnno1962/ApportablePlugin/HEAD/InjectionDemo/InjectionDemo/Icon.png -------------------------------------------------------------------------------- /ApportablePlugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Classes/APDebugController.h: -------------------------------------------------------------------------------- 1 | // 2 | // APDebugController.h 3 | // ApportablePlugin 4 | // 5 | // Created by John Holdsworth on 01/06/2014. 6 | // 7 | // 8 | 9 | #import "APConsoleController.h" 10 | 11 | @interface APDebugController : APConsoleController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Classes/APTextView.h: -------------------------------------------------------------------------------- 1 | // 2 | // APTextView.h 3 | // ApportablePlugin 4 | // 5 | // Created by John Holdsworth on 01/05/2014. 6 | // Copyright (c) 2014 John Holdsworth. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface APTextView : NSTextView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Classes/APLogController.h: -------------------------------------------------------------------------------- 1 | // 2 | // APLogController.h 3 | // ApportablePlugin 4 | // 5 | // Created by John Holdsworth on 01/05/2014. 6 | // Copyright (c) 2014 John Holdsworth. All rights reserved. 7 | // 8 | 9 | #import "APConsoleController.h" 10 | 11 | @interface APLogController : APConsoleController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo/INViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // INViewController.h 3 | // InjectionDemo 4 | // 5 | // Created by John Holdsworth on 22/05/2012. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface INViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo/INRoseView.h: -------------------------------------------------------------------------------- 1 | // 2 | // INRoseView.h 3 | // InjectionDemo 4 | // 5 | // Created by John Holdsworth on 12/05/2012. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // $Id$ 8 | // 9 | 10 | #import 11 | 12 | @interface INRoseView : UIView 13 | 14 | @property (strong, nonatomic) IBOutlet UIButton *button; 15 | 16 | - (IBAction)animate:sender; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo/InjectionDemo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'InjectionDemo' target in the 'InjectionDemo' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_4_0 8 | #warning "This project uses features only available in iOS SDK 4.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /Classes/APPluginMenuController.h: -------------------------------------------------------------------------------- 1 | // 2 | // APPluginMenuController.h 3 | // ApportablePlugin 4 | // 5 | // Created by John Holdsworth on 01/05/2014. 6 | // Copyright (c) 2014 John Holdsworth. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface APPluginMenuController : NSObject 12 | 13 | @property (nonatomic,strong) NSWindow *lastKeyWindow; 14 | 15 | + (APPluginMenuController *)sharedPlugin; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo/INAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // INAppDelegate.h 3 | // InjectionDemo 4 | // 5 | // Created by John Holdsworth on 22/05/2012. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class INViewController; 12 | 13 | @interface INAppDelegate : UIResponder 14 | 15 | @property (strong, nonatomic) UIWindow *window; 16 | @property (strong, nonatomic) INViewController *viewController; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // InjectionDemo 4 | // 5 | // Created by John Holdsworth on 22/05/2012. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "INAppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([INAppDelegate class])); 17 | } 18 | } 19 | 20 | #ifdef ANDROID 21 | #import "../../APLiveCoding.m" 22 | #endif 23 | -------------------------------------------------------------------------------- /prepare.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # prepare.py 4 | # ApportablePlugin 5 | # 6 | # Created by John Holdsworth on 11/05/2014. 7 | # 8 | 9 | import sys 10 | from subprocess import Popen, PIPE, call 11 | 12 | implementation = sys.argv[1] 13 | 14 | main_m = Popen(["find", ".", "-name", "main.m*", "-print"], 15 | stdout=PIPE).stdout.read().split( "\n" )[0] 16 | 17 | call(["chmod", "+w", main_m]) 18 | 19 | open(main_m, "a").write(""" 20 | //#ifdef DEBUG 21 | #import "%s" 22 | //#endif 23 | """ % implementation) 24 | 25 | call(["open", main_m]) 26 | -------------------------------------------------------------------------------- /Classes/APLiveCoding.h: -------------------------------------------------------------------------------- 1 | // 2 | // APLiveCoding.h 3 | // ApportablePlugin 4 | // 5 | // Created by John Holdsworth on 03/05/2014. 6 | // Copyright (c) 2014 John Holdsworth. All rights reserved. 7 | // 8 | 9 | #ifndef _APLiveCoding_h_ 10 | #define _APLiveCoding_h_ 11 | 12 | #import 13 | 14 | #define kINNotification @"INJECTION_BUNDLE_NOTIFICATION" 15 | 16 | #ifdef DEBUG 17 | #define _instatic 18 | #else 19 | #define _instatic static 20 | #endif 21 | 22 | #define _inglobal 23 | 24 | #define _inval( _val... ) = _val 25 | 26 | @interface APLiveCoding : NSObject 27 | 28 | + (void)loadedClass:(Class)newClass notify:(BOOL)notify; 29 | + (void)loadedNotify:(BOOL)notify hook:(void *)hook; 30 | 31 | @end 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /Classes/APConsoleController.h: -------------------------------------------------------------------------------- 1 | // 2 | // APConsoleController.h 3 | // ApportablePlugin 4 | // 5 | // Created by John Holdsworth on 01/05/2014. 6 | // Copyright (c) 2014 John Holdsworth. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface APConsoleController : NSObject 12 | 13 | @property (nonatomic,assign) IBOutlet NSTextView *console; 14 | @property (nonatomic,strong) NSTask *task; 15 | 16 | - (instancetype)initNib:(NSString *)nibName project:(NSString *)projectRoot command:(NSString *)command; 17 | - (void)runTask:(NSTask *)task sendOnCompletetion:(NSString *)gdbCommand; 18 | - (BOOL)handleTextViewInput:(NSString *)characters; 19 | - (void)insertText:(NSString *)output; 20 | - (void)sendTask:(NSString *)input; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Classes/APTextView.m: -------------------------------------------------------------------------------- 1 | // 2 | // APTextView.m 3 | // ApportablePlugin 4 | // 5 | // Created by John Holdsworth on 01/05/2014. 6 | // Copyright (c) 2014 John Holdsworth. All rights reserved. 7 | // 8 | 9 | #import "APTextView.h" 10 | #import "APConsoleController.h" 11 | 12 | @implementation APTextView 13 | 14 | - (void)keyDown:(NSEvent *)theEvent 15 | { 16 | if ( ![(APConsoleController *)self.delegate handleTextViewInput:[theEvent characters]] ) 17 | [super keyDown:theEvent]; 18 | } 19 | 20 | - (void)paste:(id)sender 21 | { 22 | NSPasteboard *pb = [NSPasteboard generalPasteboard]; 23 | NSString *input = [pb stringForType:NSPasteboardTypeString]; 24 | if ( ![(APConsoleController *)self.delegate handleTextViewInput:input] ) 25 | [super paste:sender]; 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo/INViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // INViewController.m 3 | // InjectionDemo 4 | // 5 | // Created by John Holdsworth on 22/05/2012. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "INViewController.h" 10 | 11 | @interface INViewController () 12 | 13 | @end 14 | 15 | @implementation INViewController 16 | 17 | - (void)viewDidLoad 18 | { 19 | [super viewDidLoad]; 20 | // Do any additional setup after loading the view, typically from a nib. 21 | } 22 | 23 | - (void)viewDidUnload 24 | { 25 | [super viewDidUnload]; 26 | // Release any retained subviews of the main view. 27 | } 28 | 29 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 30 | { 31 | if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { 32 | return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown); 33 | } else { 34 | return YES; 35 | } 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.johnholdsworth.ApportablePlugin 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | ${CURRENT_PROJECT_VERSION} 19 | CFBundleVersion 20 | ${CURRENT_PROJECT_VERSION} 21 | NSPrincipalClass 22 | APPluginMenuController 23 | XCGCReady 24 | 25 | XCPluginHasUI 26 | 27 | XC4Compatible 28 | 29 | DVTPlugInCompatibilityUUIDs 30 | 31 | 63FC1C47-140D-42B0-BB4D-A10B2D225574 32 | 37B30044-3B14-46BA-ABAA-F01000C27B63 33 | A2E4D43F-41F4-4FB9-BB94-7177011C9AED 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo/InjectionDemo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.johnholdsworth.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleIconFile 14 | Icon.png 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | 1.0 27 | LSRequiresIPhoneOS 28 | 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ApportablePlugin.xcodeproj/project.xcworkspace/xcshareddata/ApportablePlugin.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | E29DE24F-1B66-402E-9381-A192C6AFF340 9 | IDESourceControlProjectName 10 | ApportablePlugin 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 896251A8-7A25-4B0E-93A8-C5EA4AC48D94 14 | https://github.com/johnno1962/ApportablePlugin.git 15 | 16 | IDESourceControlProjectPath 17 | ApportablePlugin.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 896251A8-7A25-4B0E-93A8-C5EA4AC48D94 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/johnno1962/ApportablePlugin.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | 896251A8-7A25-4B0E-93A8-C5EA4AC48D94 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 896251A8-7A25-4B0E-93A8-C5EA4AC48D94 36 | IDESourceControlWCCName 37 | ApportablePlugin 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo/INAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // INAppDelegate.m 3 | // InjectionDemo 4 | // 5 | // Created by John Holdsworth on 22/05/2012. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "INAppDelegate.h" 10 | 11 | #import "INViewController.h" 12 | 13 | @implementation INAppDelegate 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 16 | { 17 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 18 | // Override point for customization after application launch. 19 | self.viewController = [[INViewController alloc] initWithNibName:@"INViewController" bundle:nil]; 20 | self.window.rootViewController = self.viewController; 21 | [self.window makeKeyAndVisible]; 22 | return YES; 23 | } 24 | 25 | - (void)applicationWillResignActive:(UIApplication *)application 26 | { 27 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 28 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 29 | } 30 | 31 | - (void)applicationDidEnterBackground:(UIApplication *)application 32 | { 33 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 34 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 35 | } 36 | 37 | - (void)applicationWillEnterForeground:(UIApplication *)application 38 | { 39 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 40 | } 41 | 42 | - (void)applicationDidBecomeActive:(UIApplication *)application 43 | { 44 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 45 | } 46 | 47 | - (void)applicationWillTerminate:(UIApplication *)application 48 | { 49 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /Classes/APDebugController.m: -------------------------------------------------------------------------------- 1 | // 2 | // APDebugController.m 3 | // ApportablePlugin 4 | // 5 | // Created by John Holdsworth on 01/06/2014. 6 | // 7 | // 8 | 9 | #import "APDebugController.h" 10 | 11 | #import "APPluginMenuController.h" 12 | 13 | @interface NSObject(APMethodsUsed) 14 | + (NSImage *)iconImage_pause; 15 | + (NSImage *)iconImage_resume; 16 | @end 17 | 18 | @interface APDebugController() 19 | 20 | @property (nonatomic,retain) IBOutlet NSView *scrollView; 21 | 22 | @property (nonatomic,retain) NSButton *pauseResume; 23 | @property (nonatomic,retain) NSTextView *debugger; 24 | 25 | @end 26 | 27 | static id pauseTarget; 28 | 29 | @implementation APDebugController 30 | 31 | - (instancetype)initNib:(NSString *)nibName project:(NSString *)projectRoot command:(NSString *)command 32 | { 33 | self = [super initNib:nibName project:projectRoot command:command]; 34 | 35 | [self findConsole:[[APPluginMenuController sharedPlugin].lastKeyWindow contentView]]; 36 | NSView *splitView = self.debugger; 37 | for ( int i=0 ; i<8 ; i++ ) 38 | splitView = [splitView superview]; 39 | self.scrollView.frame = splitView.frame; 40 | [[splitView superview] addSubview:self.scrollView]; 41 | 42 | if ( [[[self.pauseResume target] class] respondsToSelector:@selector(iconImage_pause)] ) 43 | pauseTarget = [self.pauseResume target]; 44 | self.pauseResume.enabled = TRUE; 45 | self.pauseResume.target = self; 46 | return self; 47 | } 48 | 49 | - (void)findConsole:(NSView *)view 50 | { 51 | for ( NSView *subview in [view subviews] ) { 52 | if ( [subview isKindOfClass:[NSButton class]] && 53 | [(NSButton *)subview action] == @selector(pauseOrResume:) ) 54 | self.pauseResume = (NSButton *)subview; 55 | if ( [subview class] == NSClassFromString(@"IDEConsoleTextView") ) 56 | self.debugger = (NSTextView *)subview; 57 | [self findConsole:subview]; 58 | } 59 | } 60 | 61 | - (void)pauseOrResume:sender 62 | { 63 | if ( [self.pauseResume image] == [[pauseTarget class] iconImage_pause] ) { 64 | self.pauseResume.image = [[pauseTarget class] iconImage_resume]; 65 | [self.task interrupt]; 66 | } 67 | else { 68 | self.pauseResume.image = [[pauseTarget class] iconImage_pause]; 69 | [self sendTask:@"c\n"]; 70 | } 71 | } 72 | 73 | - (void)windowWillClose:(NSNotification *)notification 74 | { 75 | self.pauseResume.image = [[pauseTarget class] iconImage_pause]; 76 | self.pauseResume.target = pauseTarget; 77 | [self.scrollView removeFromSuperview]; 78 | [super windowWillClose:notification]; 79 | } 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # An ApportablePlugin 2 | 3 | A simple plugin to run apportable commands from inside Xcode as a starting point. To use, build the project 4 | which will linstall to the correct directory and then restart Xcode. Open an apportable project and use 5 | the new menu at the end of Xcode's "Product" menu to run the apportable debug/load/log/kill commands. 6 | You can type into the console windows opened or type control-c to interrupt the command. The "apportable 7 | log" window can be filtered by entering a regular expression. Windows close automatically on sucess. 8 | 9 | ### Live Coding 10 | 11 | The plugin now also supports live coding where you can make changes to the implementation any class in a 12 | running program. The main.m of the project project must first have been slightly patched by using the 13 | menu item "Product/Apportable/Prepare". After this, when the program is running or being debugged, 14 | changes to the current selected file can be applied using the "Apportable/Patch" command. As this 15 | requires a debugging connection, if one is not already open the plugin will attach to the program. 16 | 17 | Live Coding works by #importing the changed class into a small stub of code which lists the classes 18 | being loaded which is compiled and the resulting shared library copied to phone. gdb is then messaged 19 | by the plugin to call [APLiveCoding inject:"/data/local/tmp/APLiveCodingN.so"] which loads and calls the 20 | stub in the shared library. This registers any selector references and "swizzles" the new implementations 21 | onto the original class. Remember to "Apportable/Prepare" your project to make APLiveCoding available. 22 | 23 | ### Demo App 24 | 25 | A small demo app is included in the plugin which can be opened using the "Apportable/Demo" menu item. 26 | Run the applpication using "Apportable/Load" and edit the file "INRoseView.m" and type ^X to see how 27 | changing the various hard coded values affects the displayed appearance. This will open a window to 28 | "just_attach" to the process to load the changes using gdb commands. Do not close this window if 29 | you want to make subseqent changes as patching only works in the first debug/attach window opened. 30 | 31 | ### MIT License 32 | 33 | Copyright (C) 2014 John Holdsworth 34 | 35 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 36 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 37 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 38 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 39 | 40 | The above copyright notice and this permission notice shall be included in all copies or substantial 41 | portions of the Software. 42 | 43 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 44 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 45 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 46 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 47 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 48 | -------------------------------------------------------------------------------- /Classes/APLogController.m: -------------------------------------------------------------------------------- 1 | // 2 | // APLogController.m 3 | // ApportablePlugin 4 | // 5 | // Created by John Holdsworth on 01/05/2014. 6 | // Copyright (c) 2014 John Holdsworth. All rights reserved. 7 | // 8 | 9 | #import "APLogController.h" 10 | 11 | @interface APLogController() 12 | 13 | @property (nonatomic,assign) IBOutlet NSSearchField *filter; 14 | @property (nonatomic,assign) IBOutlet NSButton *paused; 15 | 16 | @property (nonatomic,strong) NSMutableArray *lineBuffer; 17 | @property (atomic,strong) NSMutableString *incoming; 18 | @property (atomic,strong) NSLock *lock; 19 | 20 | @end 21 | 22 | @implementation APLogController 23 | 24 | - (NSString *)filterLinesByCurrentRegularExpression:(NSArray *)lines 25 | { 26 | NSMutableString *out = [[NSMutableString alloc] init]; 27 | NSRegularExpression *filterRegexp = [NSRegularExpression regularExpressionWithPattern:self.filter.stringValue 28 | options:0 error:NULL]; 29 | for ( NSString *line in lines ) { 30 | if ( !filterRegexp || 31 | [filterRegexp rangeOfFirstMatchInString:line options:0 32 | range:NSMakeRange(0, [line length])].location != NSNotFound ) { 33 | [out appendString:line]; 34 | [out appendString:@"\n"]; 35 | } 36 | } 37 | 38 | return out; 39 | } 40 | 41 | - (IBAction)filterChange:sender 42 | { 43 | self.console.string = [self filterLinesByCurrentRegularExpression:self.lineBuffer]; 44 | } 45 | 46 | - (void)insertText:(NSString *)output 47 | { 48 | if ( !self.lock ) 49 | self.lock = [[NSLock alloc] init]; 50 | 51 | [self.lock lock]; 52 | if ( !self.incoming ) 53 | self.incoming = [[NSMutableString alloc] init]; 54 | [self.incoming appendString:output]; 55 | [self.lock unlock]; 56 | 57 | dispatch_async(dispatch_get_main_queue(), ^{ 58 | [self insertIncoming]; 59 | }); 60 | 61 | } 62 | 63 | - (void)insertIncoming 64 | { 65 | if ( !self.incoming ) 66 | return; 67 | 68 | [self.lock lock]; 69 | NSMutableArray *newLlines = [[self.incoming componentsSeparatedByString:@"\n"] mutableCopy]; 70 | self.incoming = nil; 71 | [self.lock unlock]; 72 | 73 | NSUInteger lineCount = [newLlines count]; 74 | if ( lineCount && [newLlines[lineCount-1] length] == 0 ) 75 | [newLlines removeObjectAtIndex:lineCount-1]; 76 | 77 | if ( !self.lineBuffer ) 78 | self.lineBuffer = [[NSMutableArray alloc] init]; 79 | [self.lineBuffer addObjectsFromArray:newLlines]; 80 | 81 | if ( ![self.paused state] ) { 82 | NSString *filtered = [self filterLinesByCurrentRegularExpression:newLlines]; 83 | if ( [filtered length] ) 84 | [super insertText:filtered]; 85 | } 86 | 87 | } 88 | 89 | - (IBAction)pausePlay:sender 90 | { 91 | if ( [self.paused state] ) { 92 | [self.paused setImage:[self imageNamed:@"play"]]; 93 | } 94 | else { 95 | [self.paused setImage:[self imageNamed:@"pause"]]; 96 | [self filterChange:self]; 97 | } 98 | } 99 | 100 | - (NSImage *)imageNamed:(NSString *)name 101 | { 102 | return [[NSImage alloc] initWithContentsOfFile:[[NSBundle bundleForClass:[self class]] 103 | pathForResource:name ofType:@"png"]]; 104 | } 105 | 106 | @end 107 | -------------------------------------------------------------------------------- /Classes/APDebugController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /inject.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # inject.py 4 | # ApportablePlugin 5 | # 6 | # Created by John Holdsworth on 11/05/2014. 7 | # 8 | 9 | import sys 10 | from sys import argv, exit 11 | from os import environ, chdir, unlink, fdopen 12 | from subprocess import call 13 | import re 14 | 15 | sys.stdout = fdopen(sys.stdout.fileno(), 'w', 0) 16 | 17 | projectRoot = argv[1] 18 | shlib = argv[2] 19 | selectedFile= argv[3] 20 | flags = 0 21 | 22 | projName = re.search(r'/([^/]+)/?$', projectRoot).group(1); 23 | 24 | classes = list(set(re.findall(r'@implementation\s+(\w+)\b',open(selectedFile).read()))) 25 | injection = "".join(map(lambda cl:' [APLiveCoding loadedClass:[%s class] notify:%s];\n' % (cl, flags), classes)) 26 | 27 | changesFile = re.sub( r'(\.\w+)$', r'_\1', selectedFile ) 28 | 29 | open( changesFile, "w" ).write( """\ 30 | /* 31 | Generated for Injection of class implementations 32 | */ 33 | 34 | #import 35 | 36 | @interface APLiveCoding 37 | + (void)loadedClass:(Class)newClass notify:(BOOL)notify; 38 | + (void)loadedNotify:(BOOL)notify hook:(void *)hook; 39 | @end 40 | 41 | #define INJECTION_BUNDLE 42 | 43 | #undef _instatic 44 | #define _instatic extern 45 | 46 | #undef _inglobal 47 | #define _inglobal extern 48 | 49 | #undef _inval 50 | #define _inval( _val... ) /* = _val */ 51 | 52 | #import "%s" 53 | 54 | #if __cplusplus 55 | extern "C" int injectionHook(); 56 | #endif 57 | 58 | int injectionHook() { 59 | NSLog( @"injectionHook( %s ):" ); 60 | dispatch_async(dispatch_get_main_queue(), ^{ 61 | %s [APLiveCoding loadedNotify:%s hook:(void *)injectionHook]; 62 | }); 63 | return YES; 64 | } 65 | 66 | """ % (selectedFile, " ".join(classes), injection, flags)) 67 | 68 | 69 | print "\nBuilding "+changesFile 70 | chdir( environ['HOME']+"/.apportable/SDK" ) 71 | 72 | ninja = open( "Build/build.ninja" ).read(); 73 | rule = "compile_c" 74 | if ( re.match( r'\.mm$', selectedFile ) ): 75 | rule = "compile_cxx" 76 | 77 | command = re.search( r'rule %s_.*\n command = ((?:.*\$\n)*.*)' % rule, ninja ).group(1) 78 | per_file_flags = re.search( r'per_file_flags = (.*)', ninja ).group(1) 79 | tmpobj = "/tmp/injection_"+environ['USER'] 80 | 81 | command = re.sub( r'\$per_file_flags\b', per_file_flags, command ); 82 | command = re.sub( r'\$in\b', '"%s"' % changesFile, command ); 83 | command = re.sub( r'\$out\b', '"%s.o"' % tmpobj, command ); 84 | 85 | command = re.sub( r'\$\n\s+', r'', command ) 86 | command = re.sub( r'\$(.)', r'\1', command ) 87 | 88 | prjName = re.sub( r' ', r'', projName ) 89 | syslibs = "android c m v z dl log cxx stdc++ System SystemConfiguration Security CFNetwork "\ 90 | "Foundation CoreFoundation CoreGraphics CoreText BridgeKit OpenAL GLESv1_CM GLESv2 EGL xml2".split(" ") 91 | 92 | command = command + ' && ./toolchain/macosx/android-ndk/toolchains/arm-linux-androideabi-*/prebuilt/darwin-x86*/arm-linux-androideabi/bin/ld "%s.o" "Build/android-armeabi-debug/%s/apk/lib/armeabi/libverde.so" %s -shared -o "%s.so"' % \ 93 | (tmpobj, prjName, " ".join(map(lambda lib:'"sysroot/usr/lib/armeabi/lib%s.so"' % lib, syslibs)), tmpobj) 94 | 95 | if ( call( ["/bin/bash", "-c", command] ) ): 96 | print argv[0]+": *** Compile failed: "+changesFile 97 | exit(1) 98 | 99 | unlink( changesFile ) 100 | 101 | print "\nPushing to device.." 102 | if ( call( ["/bin/bash", "-c", "./bin/adb push %s.so %s 2>&1" % (tmpobj, shlib)] ) ): 103 | print argv[0]+": *** Could not push to device" 104 | exit(1) 105 | 106 | print "Injecting code changes" 107 | -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo/INRoseView.m: -------------------------------------------------------------------------------- 1 | // 2 | // INRoseView.m 3 | // InjectionDemo 4 | // 5 | // Created by John Holdsworth on 12/05/2012. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // $Id: $ 8 | // 9 | 10 | #import "INRoseView.h" 11 | 12 | static float power, radius; 13 | 14 | static float psin( float phi ) { 15 | float s = sin( phi ); 16 | return (s<0?-1:1) * powf( fabs( s ), power ) * radius; 17 | } 18 | 19 | static float pcos( float phi ) { 20 | return psin( phi + M_PI_2 ); 21 | } 22 | 23 | @interface INRoseView () 24 | 25 | @property (assign, nonatomic) IBOutlet UISlider *slider; 26 | 27 | @property (assign, nonatomic) float roseOffset; 28 | @property (assign, nonatomic) float colorOffset; 29 | @property (assign, nonatomic) BOOL animating; 30 | 31 | @end 32 | 33 | @implementation INRoseView 34 | 35 | - (void)awakeFromNib 36 | { 37 | [self animate:self]; 38 | [[NSNotificationCenter defaultCenter] 39 | addObserver:self selector:@selector(injectionBundleLoaded:) name:@"INJECTION_BUNDLE_NOTIFICATION" object:nil]; 40 | } 41 | 42 | - (void)injectionBundleLoaded:(NSNotification *)notification 43 | { 44 | NSLog( @"Injection Bundle has been loaded with code changes." ); 45 | [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO]; 46 | } 47 | 48 | - (IBAction)sliderChange:(id)sender 49 | { 50 | [self setNeedsDisplay]; 51 | } 52 | 53 | // edit method and save to see your changes take effect // 54 | - (void)drawRect:(CGRect)rect 55 | { 56 | // affects "squareness" of the spiral 57 | // reference to control panel parameter 58 | power = [self.slider value]; 59 | 60 | // spacing between lines 61 | float dphi = .1; 62 | 63 | // spacing between circuits 64 | float rphi = .9; 65 | 66 | // Drawing code 67 | CGContextRef cg = UIGraphicsGetCurrentContext(); 68 | CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB(); 69 | 70 | radius = rect.size.width/2.; 71 | 72 | // initial parameters for the spiral 73 | float x0 = radius, y0 = radius+12, phi0 = self.roseOffset, phi1 = self.roseOffset + M_PI, 74 | colorphi = self.colorOffset; 75 | 76 | 77 | // draw lines until angle phi0 catches up with phi1 78 | while ( phi0 < phi1 ) { 79 | 80 | // color rotates around color circle as lines are drawn 81 | CGFloat Y = .5, U = sin(colorphi), V = cos(colorphi); 82 | CGFloat R = Y + 1.4075 * V; 83 | CGFloat G = Y - 0.3455 * U - 0.7169 * V; 84 | CGFloat B = Y + 1.7790 * U; 85 | 86 | CGFloat cols[4] = {R,G,B,1.}; 87 | CGColorRef cgc = CGColorCreate( cs, cols ); 88 | CGContextSetStrokeColorWithColor( cg, cgc ); 89 | CGColorRelease(cgc); 90 | 91 | // draw colored line across circle 92 | CGContextMoveToPoint( cg, x0 + psin( phi0 ), y0 + pcos( phi0 ) ); 93 | CGContextAddLineToPoint( cg, x0 + psin( phi1 ), y0 + pcos( phi1 ) ); 94 | CGContextDrawPath( cg, kCGPathStroke ); 95 | 96 | // move line and color phase on. 97 | phi0 += dphi; 98 | phi1 += dphi * rphi; 99 | 100 | colorphi += dphi * 01.; 101 | } 102 | 103 | CGColorSpaceRelease(cs); 104 | } 105 | 106 | - (void)animate 107 | { 108 | if ( !self.animating ) 109 | return; 110 | 111 | // edit and save to see changes 112 | self.roseOffset -= .09; // rotate rose 113 | self.colorOffset -= .13; // rotate colors 114 | 115 | [self setNeedsDisplay]; 116 | 117 | // object oriented parameter reference 118 | float delay = 01.; 119 | [self performSelector:@selector(animate) withObject:nil afterDelay:.05*delay]; 120 | } 121 | 122 | - (IBAction)animate:sender 123 | { 124 | if ( (self.animating = !self.animating) ) 125 | [self animate]; 126 | } 127 | 128 | @end 129 | -------------------------------------------------------------------------------- /Classes/APPluginMenuController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo/en.lproj/INViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 30 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Classes/APLiveCoding.m: -------------------------------------------------------------------------------- 1 | // 2 | // APLiveCoding.m 3 | // ApportablePlugin 4 | // 5 | // Created by John Holdsworth on 03/05/2014. 6 | // Copyright (c) 2014 John Holdsworth. All rights reserved. 7 | // 8 | 9 | #ifdef ANDROID 10 | 11 | #ifndef _APLiveCoding_m_ 12 | #define _APLiveCoding_m_ 13 | 14 | #import "APLiveCoding.h" 15 | 16 | #import 17 | #import 18 | #import 19 | #import 20 | #import 21 | 22 | #define INLog NSLog 23 | 24 | @implementation UIAlertView(Injection) 25 | 26 | - (void)injectionDismiss 27 | { 28 | [self dismissWithClickedButtonIndex:0 animated:YES]; 29 | } 30 | 31 | @end 32 | 33 | @implementation APLiveCoding 34 | 35 | + (BOOL)inject:(const char *)path { 36 | NSLog( @"Loading shared library: %s", path ); 37 | void *library = dlopen( path, RTLD_NOW); 38 | if ( !library ) 39 | NSLog( @"APLiveCoding: %s", dlerror() ); 40 | else { 41 | int (*hook)() = dlsym( library, "injectionHook" ); 42 | if ( !hook ) 43 | NSLog( @"APLiveCoding: Unable to locate injectionHook() in: %s", path ); 44 | else { 45 | NSString *err = [self registerSelectorsInLibrary:path containing:hook]; 46 | if ( err ) 47 | NSLog( @"APLiveCoding: registerSelectorsInLibrary: %@", err ); 48 | return hook( path ); 49 | } 50 | } 51 | 52 | return FALSE; 53 | } 54 | 55 | + (void)loadedClass:(Class)newClass notify:(BOOL)notify 56 | { 57 | const char *className = class_getName(newClass); 58 | Class oldClass = objc_getClass(className); 59 | 60 | if ( newClass != oldClass && newClass != [self class] ) { 61 | // replace implementations for class and instance methods 62 | [self swizzle:'+' className:className onto:object_getClass(oldClass) from:object_getClass(newClass)]; 63 | [self swizzle:'-' className:className onto:oldClass from:newClass]; 64 | } 65 | 66 | NSString *msg = [[NSString alloc] initWithFormat:@"Class '%s' injected.", className]; 67 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Bundle Loaded" 68 | message:msg delegate:nil 69 | cancelButtonTitle:@"OK" otherButtonTitles:nil]; 70 | [alert show]; 71 | 72 | [alert performSelector:@selector(injectionDismiss) withObject:nil afterDelay:1.]; 73 | } 74 | 75 | + (void)loadedNotify:(BOOL)notify hook:(void *)hook 76 | { 77 | INLog( @"Bundle loaded successfully." ); 78 | [[NSNotificationCenter defaultCenter] postNotificationName:kINNotification 79 | object:nil]; 80 | } 81 | 82 | + (void)swizzle:(char)which className:(const char *)className onto:(Class)oldClass from:(Class)newClass 83 | { 84 | unsigned i, mc = 0; 85 | Method *methods = class_copyMethodList(newClass, &mc); 86 | 87 | for( i=0; ie_shoff > st.st_size ) 116 | return @"Bad segment header offset"; 117 | 118 | Elf32_Shdr *sections = (Elf32_Shdr *)(buffer+hdr->e_shoff); 119 | 120 | // assumes names section is last... 121 | const char *names = buffer+sections[hdr->e_shnum-1].sh_offset; 122 | if ( names > buffer + st.st_size ) 123 | return @"Bad section name table offset"; 124 | 125 | unsigned offset = 0, nsels = 0; 126 | 127 | for ( int i=0 ; ie_shnum ; i++ ) { 128 | Elf32_Shdr *sect = §ions[i]; 129 | const char *name = names+sect->sh_name; 130 | if ( strcmp( name, "__DATA, __objc_selrefs, literal_pointers, no_dead_strip" ) == 0 ) { 131 | offset = sect->sh_addr; 132 | nsels = sect->sh_size; 133 | } 134 | } 135 | 136 | if ( !offset ) 137 | return @"Unable to locate selrefs section"; 138 | 139 | Dl_info info; 140 | if ( !dladdr( hook, &info ) ) 141 | return @"Could not find load address"; 142 | 143 | SEL *sels = (SEL *)((char *)info.dli_fbase+offset); 144 | for ( unsigned i=0 ; i 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo.approj/targets/InjectionDemo/Release.generated: -------------------------------------------------------------------------------- 1 | { 2 | "assets": [ 3 | { 4 | "asset": "InjectionDemo/en.lproj/InfoPlist.strings", 5 | "target": "en.lproj/InfoPlist.strings" 6 | }, 7 | { 8 | "asset": "InjectionDemo/Icon.png", 9 | "target": "Icon.png" 10 | } 11 | ], 12 | "config": { 13 | "APPLICATION_FULL_NAME": "InjectionDemo", 14 | "APPLICATION_IDENTIFIER": "com.johnholdsworth.InjectionDemo", 15 | "APPLICATION_NAME": "InjectionDemo", 16 | "LONG_VERSION": "1.0", 17 | "SHORT_VERSION": "1.0", 18 | "TEMPLATE_VALUES": { 19 | "EXECUTABLE_NAME": "InjectionDemo", 20 | "PRODUCT_NAME": "InjectionDemo" 21 | } 22 | }, 23 | "defines": { 24 | "NS_BLOCK_ASSERTIONS": 1, 25 | "__IPHONE_OS_VERSION_MIN_REQUIRED": 50000 26 | }, 27 | "deps": [ 28 | "UIKit", 29 | "UIKit", 30 | "Foundation", 31 | "CoreGraphics" 32 | ], 33 | "flags": [ 34 | "-DNS_BLOCK_ASSERTIONS=1", 35 | { 36 | "flag": "-DNS_BLOCK_ASSERTIONS=1", 37 | "type": "c++" 38 | }, 39 | "-fobjc-arc", 40 | "-fasm-blocks", 41 | { 42 | "flag": "-std=gnu99", 43 | "not_type": "c++" 44 | }, 45 | { 46 | "flag": "-fgnu-keywords", 47 | "not_type": "c++" 48 | }, 49 | "-fno-asm", 50 | "-fpascal-strings", 51 | "-Wno-deprecated-declarations", 52 | "-Wreturn-type", 53 | "-Wswitch", 54 | "-Wparentheses", 55 | "-Wformat", 56 | "-Wuninitialized", 57 | "-Wunused-value", 58 | "-Wunused-variable", 59 | { 60 | "flag": "-Winvalid-offsetof", 61 | "type": "c++" 62 | }, 63 | { 64 | "flag": "-Wprotocol", 65 | "type": "objc" 66 | } 67 | ], 68 | "header_paths": [ 69 | { 70 | "header_path": "InjectionDemo-generated-files.hmap", 71 | "hmap": {}, 72 | "type": "iquote" 73 | }, 74 | { 75 | "header_path": "InjectionDemo-own-target-headers.hmap", 76 | "hmap": {}, 77 | "type": "I" 78 | }, 79 | { 80 | "header_path": "InjectionDemo-all-target-headers.hmap", 81 | "hmap": {}, 82 | "type": "I" 83 | }, 84 | { 85 | "header_path": "InjectionDemo-project-headers.hmap", 86 | "hmap": { 87 | "INAppDelegate.h": { 88 | "key": "INAppDelegate.h", 89 | "prefix": "InjectionDemo/", 90 | "suffix": "INAppDelegate.h" 91 | }, 92 | "INRoseView.h": { 93 | "key": "INRoseView.h", 94 | "prefix": "InjectionDemo/", 95 | "suffix": "INRoseView.h" 96 | }, 97 | "INViewController.h": { 98 | "key": "INViewController.h", 99 | "prefix": "InjectionDemo/", 100 | "suffix": "INViewController.h" 101 | }, 102 | "InjectionDemo-Prefix.pch": { 103 | "key": "InjectionDemo-Prefix.pch", 104 | "prefix": "InjectionDemo/", 105 | "suffix": "InjectionDemo-Prefix.pch" 106 | } 107 | }, 108 | "type": "iquote" 109 | }, 110 | { 111 | "header_path": "/var/folders/nh/gqmp6jxn4tn2tyhwqdcwcpkc0000gn/T/tmpI1QPpl/BUILT_PRODUCTS_DIR/include", 112 | "type": "I" 113 | }, 114 | { 115 | "header_path": "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include", 116 | "type": "I" 117 | }, 118 | { 119 | "header_path": "/var/folders/nh/gqmp6jxn4tn2tyhwqdcwcpkc0000gn/T/tmpI1QPpl/DERIVED_FILE_DIR/armv7", 120 | "type": "I" 121 | }, 122 | { 123 | "header_path": "/var/folders/nh/gqmp6jxn4tn2tyhwqdcwcpkc0000gn/T/tmpI1QPpl/DERIVED_FILE_DIR", 124 | "type": "I" 125 | } 126 | ], 127 | "infoplists": [ 128 | "./InjectionDemo/InjectionDemo-Info.plist" 129 | ], 130 | "libs": [], 131 | "modules": [], 132 | "pchs": [ 133 | "./InjectionDemo/InjectionDemo-Prefix.pch" 134 | ], 135 | "sources": [ 136 | { 137 | "defines": {}, 138 | "flags": [], 139 | "header_paths": [], 140 | "language": "objc", 141 | "source": "InjectionDemo/INAppDelegate.m" 142 | }, 143 | { 144 | "defines": {}, 145 | "flags": [], 146 | "header_paths": [], 147 | "language": "objc", 148 | "source": "InjectionDemo/INRoseView.m" 149 | }, 150 | { 151 | "defines": {}, 152 | "flags": [], 153 | "header_paths": [], 154 | "language": "objc", 155 | "source": "InjectionDemo/INViewController.m" 156 | }, 157 | { 158 | "defines": {}, 159 | "flags": [], 160 | "header_paths": [], 161 | "language": "objc", 162 | "source": "InjectionDemo/main.m" 163 | } 164 | ], 165 | "storyboards": [], 166 | "type": "app", 167 | "version": "3", 168 | "xcdatamodels": [], 169 | "xcode_project": "InjectionDemo.xcodeproj", 170 | "xibs": [ 171 | { 172 | "target": null, 173 | "xib": "InjectionDemo/en.lproj/INViewController.xib" 174 | } 175 | ] 176 | } -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo.approj/targets/InjectionDemo/Release.final: -------------------------------------------------------------------------------- 1 | { 2 | "assets": [ 3 | { 4 | "asset": "InjectionDemo/en.lproj/InfoPlist.strings", 5 | "target": "en.lproj/InfoPlist.strings" 6 | }, 7 | { 8 | "asset": "InjectionDemo/Icon.png", 9 | "target": "Icon.png" 10 | } 11 | ], 12 | "config": { 13 | "APPLICATION_FULL_NAME": "InjectionDemo", 14 | "APPLICATION_IDENTIFIER": "com.johnholdsworth.InjectionDemo", 15 | "APPLICATION_NAME": "InjectionDemo", 16 | "FEATURES": [ 17 | "portrait" 18 | ], 19 | "ICU_CONFIG": "normal", 20 | "LONG_VERSION": "1.0", 21 | "SHORT_VERSION": "1.0", 22 | "TEMPLATE_VALUES": { 23 | "EXECUTABLE_NAME": "InjectionDemo", 24 | "PRODUCT_NAME": "InjectionDemo" 25 | } 26 | }, 27 | "defines": { 28 | "NS_BLOCK_ASSERTIONS": 1, 29 | "__IPHONE_OS_VERSION_MIN_REQUIRED": 50000 30 | }, 31 | "deps": [ 32 | "UIKit", 33 | "UIKit", 34 | "Foundation", 35 | "CoreGraphics" 36 | ], 37 | "flags": [ 38 | "-DNS_BLOCK_ASSERTIONS=1", 39 | { 40 | "flag": "-DNS_BLOCK_ASSERTIONS=1", 41 | "type": "c++" 42 | }, 43 | "-fobjc-arc", 44 | "-fasm-blocks", 45 | { 46 | "flag": "-std=gnu99", 47 | "not_type": "c++" 48 | }, 49 | { 50 | "flag": "-fgnu-keywords", 51 | "not_type": "c++" 52 | }, 53 | "-fno-asm", 54 | "-fpascal-strings", 55 | "-Wno-deprecated-declarations", 56 | "-Wreturn-type", 57 | "-Wswitch", 58 | "-Wparentheses", 59 | "-Wformat", 60 | "-Wuninitialized", 61 | "-Wunused-value", 62 | "-Wunused-variable", 63 | { 64 | "flag": "-Winvalid-offsetof", 65 | "type": "c++" 66 | }, 67 | { 68 | "flag": "-Wprotocol", 69 | "type": "objc" 70 | } 71 | ], 72 | "header_paths": [ 73 | { 74 | "header_path": "InjectionDemo-generated-files.hmap", 75 | "hmap": {}, 76 | "type": "iquote" 77 | }, 78 | { 79 | "header_path": "InjectionDemo-own-target-headers.hmap", 80 | "hmap": {}, 81 | "type": "I" 82 | }, 83 | { 84 | "header_path": "InjectionDemo-all-target-headers.hmap", 85 | "hmap": {}, 86 | "type": "I" 87 | }, 88 | { 89 | "header_path": "InjectionDemo-project-headers.hmap", 90 | "hmap": { 91 | "INAppDelegate.h": { 92 | "key": "INAppDelegate.h", 93 | "prefix": "InjectionDemo/", 94 | "suffix": "INAppDelegate.h" 95 | }, 96 | "INRoseView.h": { 97 | "key": "INRoseView.h", 98 | "prefix": "InjectionDemo/", 99 | "suffix": "INRoseView.h" 100 | }, 101 | "INViewController.h": { 102 | "key": "INViewController.h", 103 | "prefix": "InjectionDemo/", 104 | "suffix": "INViewController.h" 105 | }, 106 | "InjectionDemo-Prefix.pch": { 107 | "key": "InjectionDemo-Prefix.pch", 108 | "prefix": "InjectionDemo/", 109 | "suffix": "InjectionDemo-Prefix.pch" 110 | } 111 | }, 112 | "type": "iquote" 113 | }, 114 | { 115 | "header_path": "/var/folders/nh/gqmp6jxn4tn2tyhwqdcwcpkc0000gn/T/tmpI1QPpl/BUILT_PRODUCTS_DIR/include", 116 | "type": "I" 117 | }, 118 | { 119 | "header_path": "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include", 120 | "type": "I" 121 | }, 122 | { 123 | "header_path": "/var/folders/nh/gqmp6jxn4tn2tyhwqdcwcpkc0000gn/T/tmpI1QPpl/DERIVED_FILE_DIR/armv7", 124 | "type": "I" 125 | }, 126 | { 127 | "header_path": "/var/folders/nh/gqmp6jxn4tn2tyhwqdcwcpkc0000gn/T/tmpI1QPpl/DERIVED_FILE_DIR", 128 | "type": "I" 129 | } 130 | ], 131 | "infoplists": [ 132 | "./InjectionDemo/InjectionDemo-Info.plist" 133 | ], 134 | "java_libs": [], 135 | "java_res_dirs": [], 136 | "java_sourcepaths": [], 137 | "java_sources": [], 138 | "libs": [], 139 | "link_flags": [], 140 | "modules": [], 141 | "pchs": [ 142 | "./InjectionDemo/InjectionDemo-Prefix.pch" 143 | ], 144 | "sources": [ 145 | { 146 | "defines": {}, 147 | "flags": [], 148 | "header_paths": [], 149 | "language": "objc", 150 | "source": "InjectionDemo/INAppDelegate.m" 151 | }, 152 | { 153 | "defines": {}, 154 | "flags": [], 155 | "header_paths": [], 156 | "language": "objc", 157 | "source": "InjectionDemo/INRoseView.m" 158 | }, 159 | { 160 | "defines": {}, 161 | "flags": [], 162 | "header_paths": [], 163 | "language": "objc", 164 | "source": "InjectionDemo/INViewController.m" 165 | }, 166 | { 167 | "defines": {}, 168 | "flags": [], 169 | "header_paths": [], 170 | "language": "objc", 171 | "source": "InjectionDemo/main.m" 172 | } 173 | ], 174 | "storyboards": [], 175 | "type": "app", 176 | "version": "3", 177 | "xcdatamodels": [], 178 | "xcode_project": "InjectionDemo.xcodeproj", 179 | "xibs": [ 180 | { 181 | "target": null, 182 | "xib": "InjectionDemo/en.lproj/INViewController.xib" 183 | } 184 | ] 185 | } -------------------------------------------------------------------------------- /Classes/APPluginMenuController.m: -------------------------------------------------------------------------------- 1 | // 2 | // APPluginMenuController.m 3 | // ApportablePlugin 4 | // 5 | // Created by John Holdsworth on 01/05/2014. 6 | // Copyright (c) 2014 John Holdsworth. All rights reserved. 7 | // 8 | 9 | #import "APPluginMenuController.h" 10 | 11 | #import "APDebugController.h" 12 | #import "APLogController.h" 13 | 14 | static APPluginMenuController *apportablePlugin; 15 | 16 | @interface APPluginMenuController() 17 | 18 | @property (nonatomic,strong) IBOutlet NSMenuItem *apportableMenu; 19 | @property (nonatomic,strong) NSTextView *lastTextView; 20 | 21 | @end 22 | 23 | @implementation APPluginMenuController 24 | 25 | + (void)pluginDidLoad:(NSBundle *)plugin 26 | { 27 | static dispatch_once_t onceToken; 28 | dispatch_once(&onceToken, ^{ 29 | apportablePlugin = [[self alloc] init]; 30 | [[NSNotificationCenter defaultCenter] addObserver:apportablePlugin 31 | selector:@selector(applicationDidFinishLaunching:) 32 | name:NSApplicationDidFinishLaunchingNotification object:nil]; 33 | }); 34 | } 35 | 36 | + (APPluginMenuController *)sharedPlugin 37 | { 38 | return apportablePlugin; 39 | } 40 | 41 | - (void)applicationDidFinishLaunching:(NSNotification *)notification 42 | { 43 | if ( ![[NSBundle bundleForClass:[self class]] loadNibNamed:@"APPluginMenuController" owner:self topLevelObjects:NULL] ) 44 | NSLog( @"APPluginMenuController: Could not load interface." ); 45 | 46 | NSMenu *productMenu = [[[NSApp mainMenu] itemWithTitle:@"Product"] submenu]; 47 | [productMenu addItem:[NSMenuItem separatorItem]]; 48 | [productMenu addItem:self.apportableMenu]; 49 | 50 | [[NSNotificationCenter defaultCenter] addObserver:self 51 | selector:@selector(selectionDidChange:) 52 | name:NSTextViewDidChangeSelectionNotification object:nil]; 53 | } 54 | 55 | - (void)selectionDidChange:(NSNotification *)notification 56 | { 57 | id object = [notification object]; 58 | if ([object isKindOfClass:NSClassFromString(@"DVTSourceTextView")] && 59 | [[object delegate] respondsToSelector:@selector(document)]) 60 | self.lastTextView = object; 61 | } 62 | 63 | - (NSString *)selectedFileSaving:(BOOL)save 64 | { 65 | NSDocument *doc = [(id)[self.lastTextView delegate] document]; 66 | if ( save ) 67 | [doc saveDocument:self]; 68 | return [[doc fileURL] path]; 69 | } 70 | 71 | - (NSString *)projectRoot 72 | { 73 | NSWindow *keyWindow = [NSApp keyWindow]; 74 | if ( ![keyWindow respondsToSelector:@selector(document)] ) 75 | keyWindow = self.lastKeyWindow; 76 | else 77 | self.lastKeyWindow = keyWindow; 78 | 79 | NSDocument *workspace = [(id)[self.lastKeyWindow delegate] document]; 80 | if ( ![workspace isKindOfClass:NSClassFromString(@"IDEWorkspaceDocument")] ) 81 | return nil; 82 | 83 | NSString *documentPath = [[workspace fileURL] path]; 84 | static NSRegularExpression *projRootRegexp; 85 | if ( !projRootRegexp ) 86 | projRootRegexp = [NSRegularExpression regularExpressionWithPattern:@"^(.*?)/([^/]+)\\.(xcodeproj|xcworkspace)" 87 | options:0 error:NULL]; 88 | 89 | NSArray *matches = [projRootRegexp matchesInString:documentPath options:0 range:NSMakeRange(0, [documentPath length])]; 90 | return [matches count] ? [documentPath substringWithRange:[matches[0] rangeAtIndex:1]] : nil; 91 | } 92 | 93 | static __weak APConsoleController *debugger; 94 | static NSString *debugProjectRoot; 95 | static int revision; 96 | 97 | - (BOOL)validateMenuItem:(NSMenuItem *)menuItem 98 | { 99 | if ( [menuItem action] == @selector(demo:) ) 100 | return YES; 101 | else if ( [menuItem action] == @selector(patch:) ) { 102 | NSString *selectedFile = [self selectedFileSaving:NO]; 103 | return ([selectedFile hasSuffix:@".m"] || [selectedFile hasSuffix:@".mm"]) && debugProjectRoot; 104 | } 105 | else 106 | return [self projectRoot] != nil; 107 | } 108 | 109 | - (void)startDebugger:(NSString *)command 110 | { 111 | #pragma clang diagnostic push 112 | #pragma clang diagnostic ignored "-Warc-unsafe-retained-assign" 113 | debugger = [[APDebugController alloc] initNib:@"APDebugController" 114 | project:debugProjectRoot 115 | command:command]; 116 | #pragma clang diagnostic pop 117 | } 118 | 119 | - (IBAction)prepare:sender 120 | { 121 | NSBundle *bundle = [NSBundle bundleForClass:[self class]]; 122 | (void)[[APConsoleController alloc] initNib:@"APConsoleWindow" project:[self projectRoot] 123 | command:[NSString stringWithFormat:@"\"%@\" \"%@\" 2>&1", 124 | [bundle pathForResource:@"prepare" ofType:@"py"], 125 | [bundle pathForResource:@"APLiveCoding" ofType:@"m"]]]; 126 | } 127 | 128 | - (IBAction)debug:sender 129 | { 130 | debugProjectRoot = [self projectRoot]; 131 | [self startDebugger:@"apportable debug"]; 132 | [debugger sendTask:@"c\n"]; 133 | } 134 | 135 | - (IBAction)attach:sender 136 | { 137 | if ( !debugProjectRoot ) 138 | debugProjectRoot = [self projectRoot]; 139 | [self startDebugger:@"apportable just_attach"]; 140 | } 141 | 142 | - (IBAction)patch:sender 143 | { 144 | if ( !debugger && sender ) 145 | [self attach:sender]; 146 | 147 | if ( debugger.task && [debugger.console.string rangeOfString:@"(gdb)"].location == NSNotFound ) { 148 | [self performSelector:@selector(patch:) withObject:nil afterDelay:.5]; 149 | return; 150 | } 151 | 152 | if ( !debugProjectRoot ) 153 | debugProjectRoot = [self projectRoot]; 154 | 155 | NSString *shlib = [NSString stringWithFormat:@"/data/local/tmp/APLiveCoding%d.so", revision++]; 156 | NSTask *task = [[NSTask alloc] init]; 157 | 158 | task.launchPath = @"/bin/bash"; 159 | task.currentDirectoryPath = debugProjectRoot; 160 | task.arguments = @[@"-c", [NSString stringWithFormat:@"\"%@\" \"%@\" \"%@\" \"%@\" 2>&1", 161 | [[NSBundle bundleForClass:[self class]] pathForResource:@"inject" ofType:@"py"], 162 | debugProjectRoot, shlib, [self selectedFileSaving:YES]]]; 163 | 164 | task.standardInput = [[NSPipe alloc] init]; 165 | task.standardOutput = [[NSPipe alloc] init]; 166 | 167 | NSString *gdbLoadCommand = [NSString stringWithFormat:@"p [APLiveCoding inject:\"%@\"]\nc\n", shlib]; 168 | [debugger runTask:task sendOnCompletetion:gdbLoadCommand]; 169 | } 170 | 171 | - (IBAction)load:sender 172 | { 173 | debugProjectRoot = [self projectRoot]; 174 | (void)[[APConsoleController alloc] initNib:@"APConsoleWindow" project:[self projectRoot] 175 | command:@"apportable load"]; 176 | } 177 | 178 | - (IBAction)kill:sender 179 | { 180 | (void)[[APDebugController alloc] initNib:@"APDebugController" project:[self projectRoot] 181 | command:@"apportable kill"]; 182 | } 183 | 184 | - (IBAction)log:sender 185 | { 186 | (void)[[APLogController alloc] initNib:@"APLogWindow" project:[self projectRoot] 187 | command:@"apportable log"]; 188 | } 189 | 190 | - (IBAction)demo:(id)sender 191 | { 192 | [[NSWorkspace sharedWorkspace] openURL:[NSURL fileURLWithPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"InjectionDemo/InjectionDemo" ofType:@"xcodeproj"]]]; 193 | } 194 | 195 | @end 196 | -------------------------------------------------------------------------------- /Classes/APLogWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /Classes/APConsoleController.m: -------------------------------------------------------------------------------- 1 | // 2 | // APConsoleController.m 3 | // ApportablePlugin 4 | // 5 | // Created by John Holdsworth on 01/05/2014. 6 | // Copyright (c) 2014 John Holdsworth. All rights reserved. 7 | // 8 | 9 | #import "APConsoleController.h" 10 | 11 | static NSMutableArray *visibleControllers; 12 | 13 | @interface APConsoleController() 14 | 15 | @property (nonatomic,strong) IBOutlet NSWindow *window; 16 | @property (nonatomic,strong) IBOutlet NSMenuItem *separator; 17 | @property (nonatomic,strong) IBOutlet NSMenuItem *menuItem; 18 | 19 | @property (nonatomic,strong) NSMutableArray *inputHistory; 20 | @property (nonatomic,assign) NSUInteger historyPointer; 21 | @property (nonatomic,assign) NSUInteger startBuffered; 22 | 23 | @end 24 | 25 | @implementation APConsoleController 26 | 27 | - (instancetype)initNib:(NSString *)nibName project:(NSString *)projectRoot command:(NSString *)command 28 | { 29 | if ( (self = [super init]) && projectRoot ) { 30 | if ( !visibleControllers ) 31 | visibleControllers = [[NSMutableArray alloc] init]; 32 | [visibleControllers addObject:self]; 33 | 34 | if ( ![[NSBundle bundleForClass:[self class]] loadNibNamed:nibName owner:self topLevelObjects:NULL] ) 35 | NSLog( @"APConsoleController: Could not load interface '%@'", nibName ); 36 | 37 | if ( self.window ) { 38 | // need to add to Windows menu manually 39 | // for some reason this is not reliable 40 | self.menuItem.title = command; 41 | 42 | NSMenu *windowMenu = [self windowMenu]; 43 | NSInteger where = [windowMenu indexOfItemWithTitle:@"Bring All to Front"]; 44 | if ( where <= 0 ) 45 | NSLog( @"AppportablePlugin: Could not locate Window menu item" ); 46 | else 47 | { 48 | [windowMenu insertItem:self.separator atIndex:where+1]; 49 | [windowMenu insertItem:self.menuItem atIndex:where+2]; 50 | } 51 | 52 | self.window.title = command; 53 | self.window.representedFilename = projectRoot; 54 | [self.window makeKeyAndOrderFront:self]; 55 | } 56 | 57 | self.task = [[NSTask alloc] init]; 58 | self.task.launchPath = @"/bin/bash"; 59 | self.task.currentDirectoryPath = projectRoot; 60 | self.task.arguments = @[@"-c", [NSString stringWithFormat:@"export PATH=" 61 | "\"~/.apportable/SDK/bin:$PATH\" && exec %@ 2>&1", command]]; 62 | 63 | self.task.standardInput = [[NSPipe alloc] init]; 64 | self.task.standardOutput = [[NSPipe alloc] init]; 65 | 66 | [self runTask:self.task sendOnCompletetion:nil]; 67 | } 68 | 69 | return self; 70 | } 71 | 72 | - (NSMenu *)windowMenu { 73 | return [[[NSApp mainMenu] itemWithTitle:@"Window"] submenu]; 74 | } 75 | 76 | /* 77 | * Thanks to NSTask tutorial by Andy Pereira: http://www.raywenderlich.com/36537/nstask-tutorial 78 | */ 79 | 80 | - (void)runTask:(NSTask *)aTask sendOnCompletetion:(NSString *)gdbCommand 81 | { 82 | dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); 83 | dispatch_async(backgroundQueue, ^{ 84 | 85 | @try { 86 | NSFileHandle *readHandle = [aTask.standardOutput fileHandleForReading]; 87 | [readHandle waitForDataInBackgroundAndNotify]; 88 | 89 | id observer = [[NSNotificationCenter defaultCenter] addObserverForName:NSFileHandleDataAvailableNotification 90 | object:readHandle queue:nil 91 | usingBlock:^(NSNotification *notification) { 92 | 93 | NSData *outputData = [readHandle availableData]; 94 | NSString *output = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding]; 95 | 96 | if ( output ) 97 | [self insertText:output]; 98 | 99 | [readHandle waitForDataInBackgroundAndNotify]; 100 | }]; 101 | 102 | [aTask launch]; 103 | [aTask waitUntilExit]; 104 | 105 | dispatch_sync(dispatch_get_main_queue(), ^{ 106 | BOOL succeeded = [aTask terminationStatus] == EXIT_SUCCESS; 107 | if ( !self.window && !gdbCommand ) 108 | [self performSelector:@selector(windowWillClose:) withObject:nil afterDelay:succeeded?0.:5.]; 109 | else if ( succeeded ) { 110 | if ( !gdbCommand ) { 111 | [self.window performSelector:@selector(close) withObject:nil afterDelay:3.]; 112 | self.task = nil; 113 | } 114 | else { 115 | [self.task interrupt]; 116 | [self performSelector:@selector(handleTextViewInput:) withObject:gdbCommand afterDelay:.1]; 117 | } 118 | } 119 | }); 120 | 121 | [[NSNotificationCenter defaultCenter] removeObserver:observer]; 122 | } 123 | @catch (NSException *exception) { 124 | self.console.string = [NSString stringWithFormat:@"Problem Running Task: %@", [exception description]]; 125 | } 126 | }); 127 | } 128 | 129 | /* 130 | * insert text into text view, overridden for filtering in APLogController.m 131 | */ 132 | - (void)insertText:(NSString *)output 133 | { 134 | dispatch_async(dispatch_get_main_queue(), ^{ 135 | [self.console setSelectedRange:NSMakeRange([self.console.string length], 0)]; 136 | [self.console insertText:output]; 137 | }); 138 | } 139 | 140 | /* 141 | * key down event in TextView, relay to running command 142 | */ 143 | - (BOOL)handleTextViewInput:(NSString *)characters 144 | { 145 | NSString *input = [characters stringByReplacingOccurrencesOfString:@"\r" withString:@"\n"]; 146 | 147 | if ( !self.inputHistory ) 148 | self.inputHistory = [[NSMutableArray alloc] init]; 149 | 150 | if ( !self.startBuffered ) 151 | self.startBuffered = [[self.console selectedRanges][0] rangeValue].location; 152 | 153 | switch ( [input characterAtIndex:0] ) { 154 | 155 | // contrl-a 156 | case 0x01: 157 | [self.console setSelectedRange:NSMakeRange(self.startBuffered, 0)]; 158 | return TRUE; 159 | 160 | // control-c 161 | case 0x03: 162 | [self.task interrupt]; 163 | self.startBuffered = 0; 164 | return TRUE; 165 | 166 | // up arrow 167 | case 0xF700: 168 | if ( self.historyPointer > 0 ) { 169 | if ( self.historyPointer == [self.inputHistory count] ) 170 | [self.inputHistory addObject:[self bufferedInput]]; 171 | self.historyPointer--; 172 | [self useHistory]; 173 | } 174 | return TRUE; 175 | 176 | // down arrow 177 | case 0xF701: 178 | if ( self.historyPointer+1 < [self.inputHistory count] ) { 179 | self.historyPointer++; 180 | [self useHistory]; 181 | } 182 | return TRUE; 183 | 184 | default: 185 | if ( [input characterAtIndex:[input length]-1] != '\n' ) 186 | return FALSE; 187 | else { 188 | [self sendTask:[[self bufferedInput] stringByAppendingString:input]]; 189 | if ( [[self bufferedInput] length] ) 190 | [self.inputHistory addObject:[self bufferedInput]]; 191 | self.historyPointer = [self.inputHistory count]; 192 | [self insertText:input]; 193 | self.startBuffered = 0; 194 | return TRUE; 195 | } 196 | } 197 | } 198 | 199 | - (NSString *)bufferedInput 200 | { 201 | return [self.console.string substringWithRange:[self bufferedRange]]; 202 | } 203 | 204 | - (NSRange)bufferedRange 205 | { 206 | NSUInteger end = [self.console.string length], start = MIN(self.startBuffered, end); 207 | return NSMakeRange(start, end>start ? end-start : 0); 208 | } 209 | 210 | - (void)useHistory 211 | { 212 | [self.console replaceCharactersInRange:[self bufferedRange] 213 | withString:self.inputHistory[self.historyPointer]]; 214 | [self.console setSelectedRange:NSMakeRange([self.console.string length], 0)]; 215 | } 216 | 217 | - (void)sendTask:(NSString *)input 218 | { 219 | @try { 220 | NSData *data = [input dataUsingEncoding:NSUTF8StringEncoding]; 221 | [[self.task.standardInput fileHandleForWriting] writeData:data]; 222 | } 223 | @catch (NSException *exception) { 224 | NSLog( @"Problem writing to task: %@", [exception description] ); 225 | } 226 | } 227 | 228 | - (void)windowWillClose:(NSNotification *)notification 229 | { 230 | [self.task terminate]; 231 | 232 | NSMenu *windowMenu = [self windowMenu]; 233 | if ( [windowMenu indexOfItem:self.separator] != -1 ) 234 | [windowMenu removeItem:self.separator]; 235 | if ( [windowMenu indexOfItem:self.menuItem] != -1 ) 236 | [windowMenu removeItem:self.menuItem]; 237 | 238 | [visibleControllers removeObject:self]; 239 | } 240 | 241 | @end 242 | -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BB3FC289155F2D5F007AA89B /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = BB3FC288155F2D5F007AA89B /* Icon.png */; }; 11 | BB82EB41156C367E00E7A6FB /* INViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = BB82EB3F156C367E00E7A6FB /* INViewController.xib */; }; 12 | BBBA5B22155EB59000421DA4 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BBBA5B21155EB59000421DA4 /* UIKit.framework */; }; 13 | BBBA5B24155EB59000421DA4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BBBA5B23155EB59000421DA4 /* Foundation.framework */; }; 14 | BBBA5B26155EB59000421DA4 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BBBA5B25155EB59000421DA4 /* CoreGraphics.framework */; }; 15 | BBBA5B2C155EB59000421DA4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = BBBA5B2A155EB59000421DA4 /* InfoPlist.strings */; }; 16 | BBBA5B2E155EB59000421DA4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BBBA5B2D155EB59000421DA4 /* main.m */; }; 17 | BBBA5B32155EB59000421DA4 /* INAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = BBBA5B31155EB59000421DA4 /* INAppDelegate.m */; }; 18 | BBBA5B3B155EB59000421DA4 /* INViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BBBA5B3A155EB59000421DA4 /* INViewController.m */; }; 19 | BBBA5B43155EB5D300421DA4 /* INRoseView.m in Sources */ = {isa = PBXBuildFile; fileRef = BBBA5B42155EB5D300421DA4 /* INRoseView.m */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | BB3FC288155F2D5F007AA89B /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = ""; }; 24 | BB82EB40156C367E00E7A6FB /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/INViewController.xib; sourceTree = ""; }; 25 | BBBA5B1D155EB59000421DA4 /* InjectionDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = InjectionDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | BBBA5B21155EB59000421DA4 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 27 | BBBA5B23155EB59000421DA4 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 28 | BBBA5B25155EB59000421DA4 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 29 | BBBA5B29155EB59000421DA4 /* InjectionDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "InjectionDemo-Info.plist"; sourceTree = ""; }; 30 | BBBA5B2B155EB59000421DA4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 31 | BBBA5B2D155EB59000421DA4 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 32 | BBBA5B2F155EB59000421DA4 /* InjectionDemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "InjectionDemo-Prefix.pch"; sourceTree = ""; }; 33 | BBBA5B30155EB59000421DA4 /* INAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = INAppDelegate.h; sourceTree = ""; }; 34 | BBBA5B31155EB59000421DA4 /* INAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = INAppDelegate.m; sourceTree = ""; }; 35 | BBBA5B39155EB59000421DA4 /* INViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = INViewController.h; sourceTree = ""; }; 36 | BBBA5B3A155EB59000421DA4 /* INViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = INViewController.m; sourceTree = ""; }; 37 | BBBA5B41155EB5D300421DA4 /* INRoseView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = INRoseView.h; sourceTree = ""; }; 38 | BBBA5B42155EB5D300421DA4 /* INRoseView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = INRoseView.m; sourceTree = ""; }; 39 | /* End PBXFileReference section */ 40 | 41 | /* Begin PBXFrameworksBuildPhase section */ 42 | BBBA5B1A155EB59000421DA4 /* Frameworks */ = { 43 | isa = PBXFrameworksBuildPhase; 44 | buildActionMask = 2147483647; 45 | files = ( 46 | BBBA5B22155EB59000421DA4 /* UIKit.framework in Frameworks */, 47 | BBBA5B24155EB59000421DA4 /* Foundation.framework in Frameworks */, 48 | BBBA5B26155EB59000421DA4 /* CoreGraphics.framework in Frameworks */, 49 | ); 50 | runOnlyForDeploymentPostprocessing = 0; 51 | }; 52 | /* End PBXFrameworksBuildPhase section */ 53 | 54 | /* Begin PBXGroup section */ 55 | BBBA5B12155EB59000421DA4 = { 56 | isa = PBXGroup; 57 | children = ( 58 | BBBA5B27155EB59000421DA4 /* InjectionDemo */, 59 | BBBA5B20155EB59000421DA4 /* Frameworks */, 60 | BBBA5B1E155EB59000421DA4 /* Products */, 61 | ); 62 | sourceTree = ""; 63 | }; 64 | BBBA5B1E155EB59000421DA4 /* Products */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | BBBA5B1D155EB59000421DA4 /* InjectionDemo.app */, 68 | ); 69 | name = Products; 70 | sourceTree = ""; 71 | }; 72 | BBBA5B20155EB59000421DA4 /* Frameworks */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | BBBA5B21155EB59000421DA4 /* UIKit.framework */, 76 | BBBA5B23155EB59000421DA4 /* Foundation.framework */, 77 | BBBA5B25155EB59000421DA4 /* CoreGraphics.framework */, 78 | ); 79 | name = Frameworks; 80 | sourceTree = ""; 81 | }; 82 | BBBA5B27155EB59000421DA4 /* InjectionDemo */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | BBBA5B41155EB5D300421DA4 /* INRoseView.h */, 86 | BBBA5B42155EB5D300421DA4 /* INRoseView.m */, 87 | BBBA5B30155EB59000421DA4 /* INAppDelegate.h */, 88 | BBBA5B31155EB59000421DA4 /* INAppDelegate.m */, 89 | BBBA5B39155EB59000421DA4 /* INViewController.h */, 90 | BBBA5B3A155EB59000421DA4 /* INViewController.m */, 91 | BB82EB3F156C367E00E7A6FB /* INViewController.xib */, 92 | BBBA5B28155EB59000421DA4 /* Supporting Files */, 93 | ); 94 | path = InjectionDemo; 95 | sourceTree = ""; 96 | }; 97 | BBBA5B28155EB59000421DA4 /* Supporting Files */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | BBBA5B2F155EB59000421DA4 /* InjectionDemo-Prefix.pch */, 101 | BBBA5B29155EB59000421DA4 /* InjectionDemo-Info.plist */, 102 | BBBA5B2A155EB59000421DA4 /* InfoPlist.strings */, 103 | BBBA5B2D155EB59000421DA4 /* main.m */, 104 | BB3FC288155F2D5F007AA89B /* Icon.png */, 105 | ); 106 | name = "Supporting Files"; 107 | sourceTree = ""; 108 | }; 109 | /* End PBXGroup section */ 110 | 111 | /* Begin PBXNativeTarget section */ 112 | BBBA5B1C155EB59000421DA4 /* InjectionDemo */ = { 113 | isa = PBXNativeTarget; 114 | buildConfigurationList = BBBA5B3E155EB59000421DA4 /* Build configuration list for PBXNativeTarget "InjectionDemo" */; 115 | buildPhases = ( 116 | BBBA5B19155EB59000421DA4 /* Sources */, 117 | BBBA5B1A155EB59000421DA4 /* Frameworks */, 118 | BBBA5B1B155EB59000421DA4 /* Resources */, 119 | ); 120 | buildRules = ( 121 | ); 122 | dependencies = ( 123 | ); 124 | name = InjectionDemo; 125 | productName = InjectionDemo; 126 | productReference = BBBA5B1D155EB59000421DA4 /* InjectionDemo.app */; 127 | productType = "com.apple.product-type.application"; 128 | }; 129 | /* End PBXNativeTarget section */ 130 | 131 | /* Begin PBXProject section */ 132 | BBBA5B14155EB59000421DA4 /* Project object */ = { 133 | isa = PBXProject; 134 | attributes = { 135 | CLASSPREFIX = IN; 136 | LastUpgradeCheck = 0430; 137 | }; 138 | buildConfigurationList = BBBA5B17155EB59000421DA4 /* Build configuration list for PBXProject "InjectionDemo" */; 139 | compatibilityVersion = "Xcode 3.2"; 140 | developmentRegion = English; 141 | hasScannedForEncodings = 0; 142 | knownRegions = ( 143 | en, 144 | ); 145 | mainGroup = BBBA5B12155EB59000421DA4; 146 | productRefGroup = BBBA5B1E155EB59000421DA4 /* Products */; 147 | projectDirPath = ""; 148 | projectRoot = ""; 149 | targets = ( 150 | BBBA5B1C155EB59000421DA4 /* InjectionDemo */, 151 | ); 152 | }; 153 | /* End PBXProject section */ 154 | 155 | /* Begin PBXResourcesBuildPhase section */ 156 | BBBA5B1B155EB59000421DA4 /* Resources */ = { 157 | isa = PBXResourcesBuildPhase; 158 | buildActionMask = 2147483647; 159 | files = ( 160 | BBBA5B2C155EB59000421DA4 /* InfoPlist.strings in Resources */, 161 | BB3FC289155F2D5F007AA89B /* Icon.png in Resources */, 162 | BB82EB41156C367E00E7A6FB /* INViewController.xib in Resources */, 163 | ); 164 | runOnlyForDeploymentPostprocessing = 0; 165 | }; 166 | /* End PBXResourcesBuildPhase section */ 167 | 168 | /* Begin PBXSourcesBuildPhase section */ 169 | BBBA5B19155EB59000421DA4 /* Sources */ = { 170 | isa = PBXSourcesBuildPhase; 171 | buildActionMask = 2147483647; 172 | files = ( 173 | BBBA5B2E155EB59000421DA4 /* main.m in Sources */, 174 | BBBA5B32155EB59000421DA4 /* INAppDelegate.m in Sources */, 175 | BBBA5B3B155EB59000421DA4 /* INViewController.m in Sources */, 176 | BBBA5B43155EB5D300421DA4 /* INRoseView.m in Sources */, 177 | ); 178 | runOnlyForDeploymentPostprocessing = 0; 179 | }; 180 | /* End PBXSourcesBuildPhase section */ 181 | 182 | /* Begin PBXVariantGroup section */ 183 | BB82EB3F156C367E00E7A6FB /* INViewController.xib */ = { 184 | isa = PBXVariantGroup; 185 | children = ( 186 | BB82EB40156C367E00E7A6FB /* en */, 187 | ); 188 | name = INViewController.xib; 189 | sourceTree = ""; 190 | }; 191 | BBBA5B2A155EB59000421DA4 /* InfoPlist.strings */ = { 192 | isa = PBXVariantGroup; 193 | children = ( 194 | BBBA5B2B155EB59000421DA4 /* en */, 195 | ); 196 | name = InfoPlist.strings; 197 | sourceTree = ""; 198 | }; 199 | /* End PBXVariantGroup section */ 200 | 201 | /* Begin XCBuildConfiguration section */ 202 | BBBA5B3C155EB59000421DA4 /* Debug */ = { 203 | isa = XCBuildConfiguration; 204 | buildSettings = { 205 | ALWAYS_SEARCH_USER_PATHS = NO; 206 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 207 | CLANG_ENABLE_OBJC_ARC = YES; 208 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 209 | COPY_PHASE_STRIP = NO; 210 | GCC_C_LANGUAGE_STANDARD = gnu99; 211 | GCC_DYNAMIC_NO_PIC = NO; 212 | GCC_OPTIMIZATION_LEVEL = 0; 213 | GCC_PREPROCESSOR_DEFINITIONS = ( 214 | "DEBUG=1", 215 | "$(inherited)", 216 | ); 217 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 218 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 219 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 220 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 221 | GCC_WARN_UNUSED_VARIABLE = YES; 222 | SDKROOT = iphoneos; 223 | TARGETED_DEVICE_FAMILY = "1,2"; 224 | }; 225 | name = Debug; 226 | }; 227 | BBBA5B3D155EB59000421DA4 /* Release */ = { 228 | isa = XCBuildConfiguration; 229 | buildSettings = { 230 | ALWAYS_SEARCH_USER_PATHS = NO; 231 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 232 | CLANG_ENABLE_OBJC_ARC = YES; 233 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 234 | COPY_PHASE_STRIP = YES; 235 | GCC_C_LANGUAGE_STANDARD = gnu99; 236 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 237 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 238 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 239 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 240 | GCC_WARN_UNUSED_VARIABLE = YES; 241 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 242 | SDKROOT = iphoneos; 243 | TARGETED_DEVICE_FAMILY = "1,2"; 244 | VALIDATE_PRODUCT = YES; 245 | }; 246 | name = Release; 247 | }; 248 | BBBA5B3F155EB59000421DA4 /* Debug */ = { 249 | isa = XCBuildConfiguration; 250 | buildSettings = { 251 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 252 | GCC_PREFIX_HEADER = "InjectionDemo/InjectionDemo-Prefix.pch"; 253 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 254 | INFOPLIST_FILE = "InjectionDemo/InjectionDemo-Info.plist"; 255 | PRODUCT_NAME = "$(TARGET_NAME)"; 256 | WRAPPER_EXTENSION = app; 257 | }; 258 | name = Debug; 259 | }; 260 | BBBA5B40155EB59000421DA4 /* Release */ = { 261 | isa = XCBuildConfiguration; 262 | buildSettings = { 263 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 264 | GCC_PREFIX_HEADER = "InjectionDemo/InjectionDemo-Prefix.pch"; 265 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 266 | INFOPLIST_FILE = "InjectionDemo/InjectionDemo-Info.plist"; 267 | PRODUCT_NAME = "$(TARGET_NAME)"; 268 | WRAPPER_EXTENSION = app; 269 | }; 270 | name = Release; 271 | }; 272 | /* End XCBuildConfiguration section */ 273 | 274 | /* Begin XCConfigurationList section */ 275 | BBBA5B17155EB59000421DA4 /* Build configuration list for PBXProject "InjectionDemo" */ = { 276 | isa = XCConfigurationList; 277 | buildConfigurations = ( 278 | BBBA5B3C155EB59000421DA4 /* Debug */, 279 | BBBA5B3D155EB59000421DA4 /* Release */, 280 | ); 281 | defaultConfigurationIsVisible = 0; 282 | defaultConfigurationName = Release; 283 | }; 284 | BBBA5B3E155EB59000421DA4 /* Build configuration list for PBXNativeTarget "InjectionDemo" */ = { 285 | isa = XCConfigurationList; 286 | buildConfigurations = ( 287 | BBBA5B3F155EB59000421DA4 /* Debug */, 288 | BBBA5B40155EB59000421DA4 /* Release */, 289 | ); 290 | defaultConfigurationIsVisible = 0; 291 | defaultConfigurationName = Release; 292 | }; 293 | /* End XCConfigurationList section */ 294 | }; 295 | rootObject = BBBA5B14155EB59000421DA4 /* Project object */; 296 | } 297 | -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo.approj/targets/InjectionDemo/Release.overrides.json: -------------------------------------------------------------------------------- 1 | { 2 | "configuration_format_version": 2, 3 | 4 | 5 | 6 | // Dictionary of global configuration parameters. 7 | // These parameters are not taken from the xcode project, 8 | // so they need to be supplied by the user. 9 | "config": { 10 | 11 | // A short name to identify the application. 12 | // Used to decide the APK filename, but not shown 13 | // anywhere in the app. 14 | // "APPLICATION_NAME": "", 15 | 16 | // The name of the application to display in the launcher 17 | // "APPLICATION_FULL_NAME": "", 18 | 19 | // The unique identifier for the application. 20 | // Normally this is in reverse DNS notation, e.g., 21 | // "com.apportable.Spin" 22 | // "APPLICATION_IDENTIFIER": "", 23 | 24 | // Short version name for the app, e.g., "1.0" 25 | // "SHORT_VERSION": "", 26 | 27 | // If you're using Google Play Game Services, put in the client id (a numerical value) 28 | // "GOOGLE_PLAY_CLIENT_ID": "1234567" 29 | 30 | // A list of features needed on the target platform. 31 | // Common features include: 32 | // "accelerometer" 33 | // "access_network_state" 34 | // "access_wifi_state" 35 | // "atc_slow_surface" 36 | // "billing" 37 | // "c2dm_receive" 38 | // "check_license" 39 | // "get_accounts" 40 | // "large_heap" 41 | // "live_wallpaper" 42 | // "multitouch" 43 | // "multitouch_distinct" 44 | // "multitouch_jazzhand" 45 | // "NFC" 46 | // "no_internet" 47 | // "notifications" 48 | // "opengles2" 49 | // "portrait" 50 | // "prefer_external_storage" 51 | // "read_phone_state" 52 | // "stencil_buffer" 53 | // "touch_filter_move" 54 | // "touchscreen" 55 | // "true_color" 56 | // "vibrate" 57 | // "wake_lock" 58 | // "write_external_storage" 59 | // "write_settings" 60 | // "xperia" 61 | //"FEATURES": [] 62 | 63 | // Preferred way of handling URLs in the code. 64 | // Leave it null for most cases. 65 | //"URL_SCHEME": null, 66 | 67 | // Key to receive remote notifications on the device. 68 | //"REMOTE_NOTIFICATION_KEY": "", 69 | 70 | // The method for adjusting the splash screen (Default.png) 71 | // to fit the native device resolution. Options are: 72 | // "aspect_fill" 73 | // "aspect_fit" 74 | // "letterbox" (the default) 75 | // "native" 76 | // "stretch" 77 | //"SPLASH_SCREEN_TYPE": "letterbox", 78 | 79 | // Path to the image to use for the app's icon. 80 | // Usually something like "./Icon.png". 81 | // "ICON": "", 82 | 83 | // A regular expression to determine which assets 84 | // should be compressed when building the final app. 85 | // By default, text assets are not compressed. Use 86 | // this to compress certain text assets. For example, 87 | // ".*.plist$" will cause all files ending in ".plist" 88 | // to be compressed. 89 | //"COMPRESSED_ASSETS_PATTERN": "", 90 | //"UNCOMPRESSED_ASSETS_PATTERN": "", 91 | 92 | // Automatically convert audio to oggs. Defaults to true. 93 | // Can be configured per file with add params and "convert" 94 | // field or with the "CONVERTABLE_AUDIO_EXTENSIONS" flag. 95 | //"CONVERT_AUDIO": false, 96 | 97 | // Comma-separated list of file extensions that are safe to convert to OGGs 98 | //"CONVERTABLE_AUDIO_EXTENSIONS": ".mp3,.wav,.caf,.m4a", 99 | 100 | // Compress PNGs with pngcrush. Defaults to true. 101 | //"COMPRESS_PNGS": false, 102 | 103 | // This will cache all converted assets (pngs, oggs, etc) 104 | // into the approj directory. This is useful if you want to 105 | // persist the changes across builds or check them in source 106 | // control so they are uses by Linux based builders. Note that 107 | // if you disable this, your final build params file will contain 108 | // absolute paths and should not be checked in. 109 | // Defaults to true. 110 | //"STORE_ASSESTS_IN_APPROJ": false, 111 | 112 | // ICU_CONFIGS specifies the ICU (International Components for Unicode) database for the project 113 | // The default is "normal" which meets the needs of most apps using NS Format classes and/or localization 114 | // "full" will specify a complete database 115 | // "none" will specify no database. Be careful - It's not always intutitive when Foundation depends upon ICU 116 | 117 | // The normal table is 2762244 bytes compressed and 8622768 uncompressed 118 | // The full table is 8396438 bytes compressed and 20775168 uncompressed 119 | 120 | // You can also configure and build your own ICU table at http://apps.icu-project.org/datacustom/ICUData50.html 121 | // Add it to the "add_params" "assets" section and specify the path to ICU_CONFIG 122 | // For example TBD 123 | 124 | "ICU_CONFIG" : "normal", 125 | 126 | //Manifest extras 127 | //A list of .xml files that contain snippets to be included in AndroidManifest.xml 128 | //inside the , and tags respectively. 129 | //"MANIFEST_EXTRAS": [], 130 | //"ACTIVITY_MANIFEST_EXTRAS": [], 131 | //"APPLICATION_MANIFEST_EXTRAS": [], 132 | 133 | // Advanced Options 134 | //"NOTIFICATION_ICON":"", 135 | //"TEMPLATE_VALUES":{}, 136 | //"OGGENC_OPTIONS":"", 137 | //"AFCONVERT_OPTIONS":"", 138 | //"PNGCRUSH_OPTIONS":"", 139 | //"MIN_SDK": 9, 140 | //"C2DM_SENDER": "", 141 | //"HARDWARE_ACCELERATED": "", 142 | //"NFC_SCHEME": "", 143 | //"MPMETRICS_API_KEY": "", 144 | //"RENAME_TARGET": true, 145 | 146 | }, 147 | 148 | // Sometimes header include path ordering matters. If so, put the ordering constraints into this 149 | // array. For example, if "./foo" has to come before "./bar", you would put: 150 | // ["./foo", "./bar"] 151 | // Note that "./some_other_include_path" doesn't appear in the list, since its order doesn't matter. 152 | // You can also specify "*", which matches everything not already constrained. This lets you put 153 | // particular paths at the beginning or end of the list. For example, ["./foo", "*", "./bar"]. 154 | "header_ordering_constraints": [], 155 | 156 | // Edit this section to add and replace files and parameters to the generated settings for this project. 157 | // If the generated settings for a particular file are incorrect, simply add it here with the settings 158 | // you need and the final build parameters will only included the version specified here. 159 | "add_params": { 160 | // A list of pch files to -include. 161 | // PCH files can be either a string, e.g., "./MyApp-Prefix.pch", 162 | // or a dictionary specifying the pch and the environment where 163 | // it should be used, e.g., 164 | // {"pch": "./prefix-android.pch", "env": {"TARGET_OS": "android"}} 165 | "pchs": [], 166 | 167 | // A list of header search paths 168 | // e.g. "./External/facebook-sdk/include" 169 | "header_paths": [], 170 | 171 | // A list of global compile flags for the project. 172 | // Flags can be either a string, e.g. "-Werror-shadow", 173 | // or a dictionary specifying the flag and the environment 174 | // that it should be used in, e.g., 175 | // {"flag": "-fstack-protector", "env": {"TARGET_OS": "android"}} 176 | "flags": [], 177 | 178 | // A dictionary of global compiler definitions for the project. 179 | // Defines can be a simple key-value pair, e.g., "DEBUG": 1, 180 | // or the value can be a dictionary specifying the value and the 181 | // environment that it should be used in, e.g., 182 | // "SOME_DEFINE": {"value": "\"yep its building on android\"", "env": {"TARGET_OS": "android"}} 183 | "defines": {}, 184 | 185 | // A list of dependencies. Typically these correspond to 186 | // frameworks in the xcode project. 187 | "deps": [], 188 | 189 | // A list of source files (e.g. .m, .mm, .c, .cc, and .cpp) files to build. 190 | // Source files can be a string, e.g. "./main.c", or a dictionary specifying 191 | // the file, any special flags, any defines, and the environment 192 | // where it should be compiled, e.g., 193 | // {"source": "./PngImageLoader.m", "flags": ["-fstack-protector"], "defines": {"PNG": 1}, "env": {"TARGET_TEXTURE_FMT": "png"}} 194 | "sources": [], 195 | 196 | // A list of glob inclusion filters for additional files. 197 | // This can also be used to replace flags on multiple files. 198 | // e.g. {"source":"./Server/Level_[0-9].m","flags": ["-fno-objc-arc"], "defines": {"NDEBUG": 1}} 199 | "sources_glob":[], 200 | 201 | // A list of assets to package with the application. 202 | // Assets can be either a string, e.g., "./Info.plist", 203 | // or a dictionary specifying the asset and the target path it should be written to 204 | // in the app, and the environment it should be included with, e.g., 205 | // {"asset": "./Resources/cube_texture.pvr.ccz", "target": "Bundled Resources/", "env": {"TARGET_TEXTURE_FMT": "pvr"}} 206 | // or a dictionary like above, but instead specifying the full target file name 207 | // for the asset, e.g., 208 | // {"asset": "./Resources/cube_texture.pvr.ccz", "target": "Bundled Resources/cube_texture.pvr.gz", "env": {"TARGET_TEXTURE_FMT": "pvr"}} 209 | "assets": [], 210 | 211 | // A list of Info.plist files. The first one in the list will be the one we consider the main Info.plist. 212 | "infoplists": [], 213 | 214 | //A list of specific java sources file to compile 215 | "java_sources": [], 216 | 217 | //A list of the java root source directories 218 | "java_sourcepaths": [], 219 | 220 | //A list of java Librarys (jars) 221 | "java_libs": [], 222 | 223 | //A list of java resource directories 224 | "java_res_dirs": [], 225 | 226 | //A list of libs to include with the APK 227 | "libs":[], 228 | 229 | //Additional linker (ld) flags. 230 | "link_flags":[], 231 | 232 | // A list of XIBs to compile into NIBs. 233 | "xibs": [], 234 | 235 | // A list of storyboards to compile into storyboardc bundles 236 | "storyboards": [], 237 | 238 | // A list of xcdatamodels to compile into momc bundles 239 | "xcdatamodels": [], 240 | 241 | //Sub projects. Example : SomeSubProject.xcodeproj should be listed as "SomeSubProject" 242 | "modules": [], 243 | }, 244 | 245 | // Edit this section to remove files and parameters from the generated #{$build_params_file} for this project. 246 | // For this section, only specify the file name as a string in the cases where you could normally 247 | // also specify an array or a dictionary. To override the generated settings for a particular 248 | // file, simply add it to the "add_params" list above with the settings you want. 249 | "remove_params": { 250 | // A list of pch files to remove from -include. 251 | // PCH files can be either a string, e.g., "./MyApp-Prefix.pch", 252 | // or a dictionary specifying the pch and the environment where 253 | // it should be used, e.g., 254 | // {"pch": "./prefix-android.pch", "env": {"TARGET_OS": "android"}} 255 | "pchs": [], 256 | 257 | // A list of header search paths. 258 | // e.g. "./External/facebook-sdk/include" 259 | "header_paths": [], 260 | 261 | // A list of global compile flags for the project. 262 | // Flags can be either a string, e.g. "-Werror-shadow", 263 | // or a dictionary specifying the flag and the environment 264 | // that it should be used in, e.g., 265 | // {"flag": "-fstack-protector", "env": {"TARGET_OS": "android"}} 266 | "flags": [], 267 | 268 | // A dictionary of global compiler definitions for the project. 269 | // Defines can be a simple key-value pair, e.g., "DEBUG": 1, 270 | // or the value can be a dictionary specifying the value and the 271 | // environment that it should be used in, e.g., 272 | // "SOME_DEFINE": {"value": "\"yep its building on android\"", "env": {"TARGET_OS": "android"}} 273 | "defines": {}, 274 | 275 | // A list of dependencies. Typically these correspond to 276 | // frameworks in the xcode project. 277 | "deps": [], 278 | 279 | // A list of source files (e.g. .m, .mm, .c, .cc, and .cpp) files to remove from the build. 280 | // e.g. "./External/Reachabilty/Reachability.m" 281 | "sources": [], 282 | 283 | // A list of glob removal filters to filter out source files. 284 | // e.g. "./Server/Level_[0-9].m" 285 | "sources_glob":[], 286 | 287 | // A list of assets to package with the application. 288 | // Assets can be either a string, e.g., "./Info.plist", 289 | // a dictionary specifying the asset, the target path it should be written to 290 | // in the app, and the environment it should be included with, e.g., 291 | // {"asset": "./Resources/cube_texture.pvr.ccz", "target_path": "Bundled Resources/", "env": {"TARGET_TEXTURE_FMT": "pvr"}} 292 | // or a dictionary like above, but instead specifying the full target file name 293 | // for the asset, e.g., 294 | // {"asset": "./Resources/cube_texture.pvr.ccz", "target_file": "Bundled Resources/cube_texture.pvr.gz", "env": {"TARGET_TEXTURE_FMT": "pvr"}} 295 | "assets": [], 296 | 297 | // A list of Info.plist files. The first one in the list will be the one we consider the main Info.plist. 298 | "infoplists": [], 299 | 300 | //A list of specific java sources file to compile 301 | "java_sources": [], 302 | 303 | //A list of the java root source directories 304 | "java_sourcepaths": [], 305 | 306 | //A list of java Librarys (jars) 307 | "java_libs": [], 308 | 309 | //A list of java resource directories 310 | "java_res_dirs": [], 311 | 312 | //A list of libs to include with the APK 313 | "libs":[], 314 | 315 | //Additional linker (ld) flags. 316 | "link_flags":[], 317 | 318 | // A list of XIBs to compile into NIBs. 319 | "xibs": [], 320 | 321 | // A list of storyboards to compile into storyboardc bundles 322 | "storyboards": [], 323 | 324 | // A list of xcdatamodels to compile into momc bundles 325 | "xcdatamodels": [], 326 | 327 | //Sub projects. Example : SomeSubProject.xcodeproj should be listed as "SomeSubProject" 328 | "modules": [], 329 | } 330 | } 331 | -------------------------------------------------------------------------------- /InjectionDemo/InjectionDemo.approj/configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "configuration_format_version": 2, 3 | 4 | "default_target": {"project": "InjectionDemo", "project_config": "Release", "target": "InjectionDemo"}, 5 | 6 | 7 | // Dictionary of global configuration parameters. 8 | // These parameters are not taken from the xcode project, 9 | // so they need to be supplied by the user. 10 | "config": { 11 | 12 | // A short name to identify the application. 13 | // Used to decide the APK filename, but not shown 14 | // anywhere in the app. 15 | // "APPLICATION_NAME": "", 16 | 17 | // The name of the application to display in the launcher 18 | // "APPLICATION_FULL_NAME": "", 19 | 20 | // The unique identifier for the application. 21 | // Normally this is in reverse DNS notation, e.g., 22 | // "com.apportable.Spin" 23 | // "APPLICATION_IDENTIFIER": "", 24 | 25 | // Short version name for the app, e.g., "1.0" 26 | // "SHORT_VERSION": "", 27 | 28 | // If you're using Google Play Game Services, put in the client id (a numerical value) 29 | // "GOOGLE_PLAY_CLIENT_ID": "1234567" 30 | 31 | // A list of features needed on the target platform. 32 | // Common features include: 33 | // "accelerometer" 34 | // "access_network_state" 35 | // "access_wifi_state" 36 | // "atc_slow_surface" 37 | // "billing" 38 | // "c2dm_receive" 39 | // "check_license" 40 | // "get_accounts" 41 | // "large_heap" 42 | // "live_wallpaper" 43 | // "multitouch" 44 | // "multitouch_distinct" 45 | // "multitouch_jazzhand" 46 | // "NFC" 47 | // "no_internet" 48 | // "notifications" 49 | // "opengles2" 50 | // "portrait" 51 | // "prefer_external_storage" 52 | // "read_phone_state" 53 | // "stencil_buffer" 54 | // "touch_filter_move" 55 | // "touchscreen" 56 | // "true_color" 57 | // "vibrate" 58 | // "wake_lock" 59 | // "write_external_storage" 60 | // "write_settings" 61 | // "xperia" 62 | "FEATURES": ["portrait"], 63 | 64 | // Preferred way of handling URLs in the code. 65 | // Leave it null for most cases. 66 | //"URL_SCHEME": null, 67 | 68 | // Key to receive remote notifications on the device. 69 | //"REMOTE_NOTIFICATION_KEY": "", 70 | 71 | // The method for adjusting the splash screen (Default.png) 72 | // to fit the native device resolution. Options are: 73 | // "aspect_fill" 74 | // "aspect_fit" 75 | // "letterbox" (the default) 76 | // "native" 77 | // "stretch" 78 | //"SPLASH_SCREEN_TYPE": "letterbox", 79 | 80 | // Path to the image to use for the app's icon. 81 | // Usually something like "./Icon.png". 82 | // "ICON": "", 83 | 84 | // A regular expression to determine which assets 85 | // should be compressed when building the final app. 86 | // By default, text assets are not compressed. Use 87 | // this to compress certain text assets. For example, 88 | // ".*.plist$" will cause all files ending in ".plist" 89 | // to be compressed. 90 | //"COMPRESSED_ASSETS_PATTERN": "", 91 | //"UNCOMPRESSED_ASSETS_PATTERN": "", 92 | 93 | // Automatically convert audio to oggs. Defaults to true. 94 | // Can be configured per file with add params and "convert" 95 | // field or with the "CONVERTABLE_AUDIO_EXTENSIONS" flag. 96 | //"CONVERT_AUDIO": false, 97 | 98 | // Comma-separated list of file extensions that are safe to convert to OGGs 99 | //"CONVERTABLE_AUDIO_EXTENSIONS": ".mp3,.wav,.caf,.m4a", 100 | 101 | // Compress PNGs with pngcrush. Defaults to true. 102 | //"COMPRESS_PNGS": false, 103 | 104 | // This will cache all converted assets (pngs, oggs, etc) 105 | // into the approj directory. This is useful if you want to 106 | // persist the changes across builds or check them in source 107 | // control so they are uses by Linux based builders. Note that 108 | // if you disable this, your final build params file will contain 109 | // absolute paths and should not be checked in. 110 | // Defaults to true. 111 | //"STORE_ASSESTS_IN_APPROJ": false, 112 | 113 | // ICU_CONFIGS specifies the ICU (International Components for Unicode) database for the project 114 | // The default is "normal" which meets the needs of most apps using NS Format classes and/or localization 115 | // "full" will specify a complete database 116 | // "none" will specify no database. Be careful - It's not always intutitive when Foundation depends upon ICU 117 | 118 | // The normal table is 2762244 bytes compressed and 8622768 uncompressed 119 | // The full table is 8396438 bytes compressed and 20775168 uncompressed 120 | 121 | // You can also configure and build your own ICU table at http://apps.icu-project.org/datacustom/ICUData50.html 122 | // Add it to the "add_params" "assets" section and specify the path to ICU_CONFIG 123 | // For example TBD 124 | 125 | "ICU_CONFIG" : "normal", 126 | 127 | //Manifest extras 128 | //A list of .xml files that contain snippets to be included in AndroidManifest.xml 129 | //inside the , and tags respectively. 130 | //"MANIFEST_EXTRAS": [], 131 | //"ACTIVITY_MANIFEST_EXTRAS": [], 132 | //"APPLICATION_MANIFEST_EXTRAS": [], 133 | 134 | // Advanced Options 135 | //"NOTIFICATION_ICON":"", 136 | //"TEMPLATE_VALUES":{}, 137 | //"OGGENC_OPTIONS":"", 138 | //"AFCONVERT_OPTIONS":"", 139 | //"PNGCRUSH_OPTIONS":"", 140 | //"MIN_SDK": 9, 141 | //"C2DM_SENDER": "", 142 | //"HARDWARE_ACCELERATED": "", 143 | //"NFC_SCHEME": "", 144 | //"MPMETRICS_API_KEY": "", 145 | //"RENAME_TARGET": true, 146 | 147 | }, 148 | 149 | // Sometimes header include path ordering matters. If so, put the ordering constraints into this 150 | // array. For example, if "./foo" has to come before "./bar", you would put: 151 | // ["./foo", "./bar"] 152 | // Note that "./some_other_include_path" doesn't appear in the list, since its order doesn't matter. 153 | // You can also specify "*", which matches everything not already constrained. This lets you put 154 | // particular paths at the beginning or end of the list. For example, ["./foo", "*", "./bar"]. 155 | "header_ordering_constraints": [], 156 | 157 | // Edit this section to add and replace files and parameters to the generated settings for this project. 158 | // If the generated settings for a particular file are incorrect, simply add it here with the settings 159 | // you need and the final build parameters will only included the version specified here. 160 | "add_params": { 161 | // A list of pch files to -include. 162 | // PCH files can be either a string, e.g., "./MyApp-Prefix.pch", 163 | // or a dictionary specifying the pch and the environment where 164 | // it should be used, e.g., 165 | // {"pch": "./prefix-android.pch", "env": {"TARGET_OS": "android"}} 166 | "pchs": [], 167 | 168 | // A list of header search paths 169 | // e.g. "./External/facebook-sdk/include" 170 | "header_paths": [], 171 | 172 | // A list of global compile flags for the project. 173 | // Flags can be either a string, e.g. "-Werror-shadow", 174 | // or a dictionary specifying the flag and the environment 175 | // that it should be used in, e.g., 176 | // {"flag": "-fstack-protector", "env": {"TARGET_OS": "android"}} 177 | "flags": [], 178 | 179 | // A dictionary of global compiler definitions for the project. 180 | // Defines can be a simple key-value pair, e.g., "DEBUG": 1, 181 | // or the value can be a dictionary specifying the value and the 182 | // environment that it should be used in, e.g., 183 | // "SOME_DEFINE": {"value": "\"yep its building on android\"", "env": {"TARGET_OS": "android"}} 184 | "defines": {}, 185 | 186 | // A list of dependencies. Typically these correspond to 187 | // frameworks in the xcode project. 188 | "deps": [], 189 | 190 | // A list of source files (e.g. .m, .mm, .c, .cc, and .cpp) files to build. 191 | // Source files can be a string, e.g. "./main.c", or a dictionary specifying 192 | // the file, any special flags, any defines, and the environment 193 | // where it should be compiled, e.g., 194 | // {"source": "./PngImageLoader.m", "flags": ["-fstack-protector"], "defines": {"PNG": 1}, "env": {"TARGET_TEXTURE_FMT": "png"}} 195 | "sources": [], 196 | 197 | // A list of glob inclusion filters for additional files. 198 | // This can also be used to replace flags on multiple files. 199 | // e.g. {"source":"./Server/Level_[0-9].m","flags": ["-fno-objc-arc"], "defines": {"NDEBUG": 1}} 200 | "sources_glob":[], 201 | 202 | // A list of assets to package with the application. 203 | // Assets can be either a string, e.g., "./Info.plist", 204 | // or a dictionary specifying the asset and the target path it should be written to 205 | // in the app, and the environment it should be included with, e.g., 206 | // {"asset": "./Resources/cube_texture.pvr.ccz", "target": "Bundled Resources/", "env": {"TARGET_TEXTURE_FMT": "pvr"}} 207 | // or a dictionary like above, but instead specifying the full target file name 208 | // for the asset, e.g., 209 | // {"asset": "./Resources/cube_texture.pvr.ccz", "target": "Bundled Resources/cube_texture.pvr.gz", "env": {"TARGET_TEXTURE_FMT": "pvr"}} 210 | "assets": [], 211 | 212 | // A list of Info.plist files. The first one in the list will be the one we consider the main Info.plist. 213 | "infoplists": [], 214 | 215 | //A list of specific java sources file to compile 216 | "java_sources": [], 217 | 218 | //A list of the java root source directories 219 | "java_sourcepaths": [], 220 | 221 | //A list of java Librarys (jars) 222 | "java_libs": [], 223 | 224 | //A list of java resource directories 225 | "java_res_dirs": [], 226 | 227 | //A list of libs to include with the APK 228 | "libs":[], 229 | 230 | //Additional linker (ld) flags. 231 | "link_flags":[], 232 | 233 | // A list of XIBs to compile into NIBs. 234 | "xibs": [], 235 | 236 | // A list of storyboards to compile into storyboardc bundles 237 | "storyboards": [], 238 | 239 | // A list of xcdatamodels to compile into momc bundles 240 | "xcdatamodels": [], 241 | 242 | //Sub projects. Example : SomeSubProject.xcodeproj should be listed as "SomeSubProject" 243 | "modules": [], 244 | }, 245 | 246 | // Edit this section to remove files and parameters from the generated #{$build_params_file} for this project. 247 | // For this section, only specify the file name as a string in the cases where you could normally 248 | // also specify an array or a dictionary. To override the generated settings for a particular 249 | // file, simply add it to the "add_params" list above with the settings you want. 250 | "remove_params": { 251 | // A list of pch files to remove from -include. 252 | // PCH files can be either a string, e.g., "./MyApp-Prefix.pch", 253 | // or a dictionary specifying the pch and the environment where 254 | // it should be used, e.g., 255 | // {"pch": "./prefix-android.pch", "env": {"TARGET_OS": "android"}} 256 | "pchs": [], 257 | 258 | // A list of header search paths. 259 | // e.g. "./External/facebook-sdk/include" 260 | "header_paths": [], 261 | 262 | // A list of global compile flags for the project. 263 | // Flags can be either a string, e.g. "-Werror-shadow", 264 | // or a dictionary specifying the flag and the environment 265 | // that it should be used in, e.g., 266 | // {"flag": "-fstack-protector", "env": {"TARGET_OS": "android"}} 267 | "flags": [], 268 | 269 | // A dictionary of global compiler definitions for the project. 270 | // Defines can be a simple key-value pair, e.g., "DEBUG": 1, 271 | // or the value can be a dictionary specifying the value and the 272 | // environment that it should be used in, e.g., 273 | // "SOME_DEFINE": {"value": "\"yep its building on android\"", "env": {"TARGET_OS": "android"}} 274 | "defines": {}, 275 | 276 | // A list of dependencies. Typically these correspond to 277 | // frameworks in the xcode project. 278 | "deps": [], 279 | 280 | // A list of source files (e.g. .m, .mm, .c, .cc, and .cpp) files to remove from the build. 281 | // e.g. "./External/Reachabilty/Reachability.m" 282 | "sources": [], 283 | 284 | // A list of glob removal filters to filter out source files. 285 | // e.g. "./Server/Level_[0-9].m" 286 | "sources_glob":[], 287 | 288 | // A list of assets to package with the application. 289 | // Assets can be either a string, e.g., "./Info.plist", 290 | // a dictionary specifying the asset, the target path it should be written to 291 | // in the app, and the environment it should be included with, e.g., 292 | // {"asset": "./Resources/cube_texture.pvr.ccz", "target_path": "Bundled Resources/", "env": {"TARGET_TEXTURE_FMT": "pvr"}} 293 | // or a dictionary like above, but instead specifying the full target file name 294 | // for the asset, e.g., 295 | // {"asset": "./Resources/cube_texture.pvr.ccz", "target_file": "Bundled Resources/cube_texture.pvr.gz", "env": {"TARGET_TEXTURE_FMT": "pvr"}} 296 | "assets": [], 297 | 298 | // A list of Info.plist files. The first one in the list will be the one we consider the main Info.plist. 299 | "infoplists": [], 300 | 301 | //A list of specific java sources file to compile 302 | "java_sources": [], 303 | 304 | //A list of the java root source directories 305 | "java_sourcepaths": [], 306 | 307 | //A list of java Librarys (jars) 308 | "java_libs": [], 309 | 310 | //A list of java resource directories 311 | "java_res_dirs": [], 312 | 313 | //A list of libs to include with the APK 314 | "libs":[], 315 | 316 | //Additional linker (ld) flags. 317 | "link_flags":[], 318 | 319 | // A list of XIBs to compile into NIBs. 320 | "xibs": [], 321 | 322 | // A list of storyboards to compile into storyboardc bundles 323 | "storyboards": [], 324 | 325 | // A list of xcdatamodels to compile into momc bundles 326 | "xcdatamodels": [], 327 | 328 | //Sub projects. Example : SomeSubProject.xcodeproj should be listed as "SomeSubProject" 329 | "modules": [], 330 | } 331 | } 332 | -------------------------------------------------------------------------------- /ApportablePlugin.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7F2EB89C145057F200E97A87 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F2EB899145057EA00E97A87 /* AppKit.framework */; }; 11 | BB26AE9F191FF6DF00702773 /* prepare.py in Resources */ = {isa = PBXBuildFile; fileRef = BB26AE9E191FF4FD00702773 /* prepare.py */; }; 12 | BB26AEA0191FF6E300702773 /* inject.py in Resources */ = {isa = PBXBuildFile; fileRef = BB26AE9D191FF4E200702773 /* inject.py */; }; 13 | BB5CF6321912DBD00052E10B /* APConsoleController.m in Sources */ = {isa = PBXBuildFile; fileRef = BB5CF6281912DBD00052E10B /* APConsoleController.m */; }; 14 | BB5CF6331912DBD00052E10B /* APConsoleWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = BB5CF6291912DBD00052E10B /* APConsoleWindow.xib */; }; 15 | BB5CF6341912DBD00052E10B /* APLogController.m in Sources */ = {isa = PBXBuildFile; fileRef = BB5CF62B1912DBD00052E10B /* APLogController.m */; }; 16 | BB5CF6351912DBD00052E10B /* APLogWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = BB5CF62C1912DBD00052E10B /* APLogWindow.xib */; }; 17 | BB5CF6371912DBD00052E10B /* APTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = BB5CF6301912DBD00052E10B /* APTextView.m */; }; 18 | BB5CF63A1912DCC50052E10B /* APPluginMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = BB5CF6391912DCC50052E10B /* APPluginMenuController.m */; }; 19 | BB82F0CD1913D15F0015AE7A /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = BB82F0CC1913D15F0015AE7A /* README.md */; }; 20 | BB9D655F19194D9E00ECF4B3 /* pause.png in Resources */ = {isa = PBXBuildFile; fileRef = BB9D655D19194D9E00ECF4B3 /* pause.png */; }; 21 | BB9D656019194D9E00ECF4B3 /* play.png in Resources */ = {isa = PBXBuildFile; fileRef = BB9D655E19194D9E00ECF4B3 /* play.png */; }; 22 | BBB0DB26193B505200B5C0D8 /* APDebugController.m in Sources */ = {isa = PBXBuildFile; fileRef = BBB0DB25193B505200B5C0D8 /* APDebugController.m */; }; 23 | BBB0DB28193B506D00B5C0D8 /* APDebugController.xib in Resources */ = {isa = PBXBuildFile; fileRef = BBB0DB27193B506D00B5C0D8 /* APDebugController.xib */; }; 24 | BBF5D8E31912DFCA0037CE2E /* APPluginMenuController.xib in Resources */ = {isa = PBXBuildFile; fileRef = BBF5D8E21912DFCA0037CE2E /* APPluginMenuController.xib */; }; 25 | DA1B5D020E64686800921439 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 089C1672FE841209C02AAC07 /* Foundation.framework */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 089C1672FE841209C02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 30 | 7F2EB899145057EA00E97A87 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 31 | 8D5B49B6048680CD000E48DA /* ApportablePlugin.xcplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ApportablePlugin.xcplugin; sourceTree = BUILT_PRODUCTS_DIR; }; 32 | 8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 33 | BB26AE9D191FF4E200702773 /* inject.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = inject.py; sourceTree = ""; }; 34 | BB26AE9E191FF4FD00702773 /* prepare.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = prepare.py; sourceTree = ""; }; 35 | BB4E31041915943D00CC72EB /* APLiveCoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APLiveCoding.h; sourceTree = ""; }; 36 | BB4E31051915943D00CC72EB /* APLiveCoding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APLiveCoding.m; sourceTree = ""; }; 37 | BB5CF6271912DBD00052E10B /* APConsoleController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APConsoleController.h; sourceTree = ""; }; 38 | BB5CF6281912DBD00052E10B /* APConsoleController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APConsoleController.m; sourceTree = ""; }; 39 | BB5CF6291912DBD00052E10B /* APConsoleWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = APConsoleWindow.xib; sourceTree = ""; }; 40 | BB5CF62A1912DBD00052E10B /* APLogController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APLogController.h; sourceTree = ""; }; 41 | BB5CF62B1912DBD00052E10B /* APLogController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APLogController.m; sourceTree = ""; }; 42 | BB5CF62C1912DBD00052E10B /* APLogWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = APLogWindow.xib; sourceTree = ""; }; 43 | BB5CF62F1912DBD00052E10B /* APTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APTextView.h; sourceTree = ""; }; 44 | BB5CF6301912DBD00052E10B /* APTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APTextView.m; sourceTree = ""; }; 45 | BB5CF6381912DCC50052E10B /* APPluginMenuController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APPluginMenuController.h; sourceTree = ""; }; 46 | BB5CF6391912DCC50052E10B /* APPluginMenuController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APPluginMenuController.m; sourceTree = ""; }; 47 | BB63E0F8160CA89800E95F5D /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; 48 | BB82F0CC1913D15F0015AE7A /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = ""; }; 49 | BB9D655D19194D9E00ECF4B3 /* pause.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = pause.png; sourceTree = ""; }; 50 | BB9D655E19194D9E00ECF4B3 /* play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play.png; sourceTree = ""; }; 51 | BBB0DB24193B505200B5C0D8 /* APDebugController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APDebugController.h; sourceTree = ""; }; 52 | BBB0DB25193B505200B5C0D8 /* APDebugController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APDebugController.m; sourceTree = ""; }; 53 | BBB0DB27193B506D00B5C0D8 /* APDebugController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = APDebugController.xib; sourceTree = ""; }; 54 | BBF5D8E21912DFCA0037CE2E /* APPluginMenuController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = APPluginMenuController.xib; sourceTree = ""; }; 55 | /* End PBXFileReference section */ 56 | 57 | /* Begin PBXFrameworksBuildPhase section */ 58 | 8D5B49B3048680CD000E48DA /* Frameworks */ = { 59 | isa = PBXFrameworksBuildPhase; 60 | buildActionMask = 2147483647; 61 | files = ( 62 | DA1B5D020E64686800921439 /* Foundation.framework in Frameworks */, 63 | 7F2EB89C145057F200E97A87 /* AppKit.framework in Frameworks */, 64 | ); 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | /* End PBXFrameworksBuildPhase section */ 68 | 69 | /* Begin PBXGroup section */ 70 | 089C166AFE841209C02AAC07 /* QuietXcode */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 7F411B0C15FABAC6002F77B6 /* Classes */, 74 | 089C167CFE841241C02AAC07 /* Resources */, 75 | 089C1671FE841209C02AAC07 /* Frameworks and Libraries */, 76 | 19C28FB8FE9D52D311CA2CBB /* Products */, 77 | ); 78 | name = QuietXcode; 79 | sourceTree = ""; 80 | }; 81 | 089C1671FE841209C02AAC07 /* Frameworks and Libraries */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 089C1672FE841209C02AAC07 /* Foundation.framework */, 85 | 7F2EB899145057EA00E97A87 /* AppKit.framework */, 86 | BB63E0F8160CA89800E95F5D /* IOKit.framework */, 87 | ); 88 | name = "Frameworks and Libraries"; 89 | sourceTree = ""; 90 | }; 91 | 089C167CFE841241C02AAC07 /* Resources */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | BB9D655D19194D9E00ECF4B3 /* pause.png */, 95 | BB9D655E19194D9E00ECF4B3 /* play.png */, 96 | BB82F0CC1913D15F0015AE7A /* README.md */, 97 | 8D5B49B7048680CD000E48DA /* Info.plist */, 98 | BB26AE9E191FF4FD00702773 /* prepare.py */, 99 | BB26AE9D191FF4E200702773 /* inject.py */, 100 | ); 101 | name = Resources; 102 | sourceTree = ""; 103 | }; 104 | 19C28FB8FE9D52D311CA2CBB /* Products */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | 8D5B49B6048680CD000E48DA /* ApportablePlugin.xcplugin */, 108 | ); 109 | name = Products; 110 | sourceTree = ""; 111 | }; 112 | 7F411B0C15FABAC6002F77B6 /* Classes */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | BB5CF6381912DCC50052E10B /* APPluginMenuController.h */, 116 | BB5CF6391912DCC50052E10B /* APPluginMenuController.m */, 117 | BBF5D8E21912DFCA0037CE2E /* APPluginMenuController.xib */, 118 | BB5CF6271912DBD00052E10B /* APConsoleController.h */, 119 | BB5CF6281912DBD00052E10B /* APConsoleController.m */, 120 | BB5CF6291912DBD00052E10B /* APConsoleWindow.xib */, 121 | BBB0DB24193B505200B5C0D8 /* APDebugController.h */, 122 | BBB0DB25193B505200B5C0D8 /* APDebugController.m */, 123 | BBB0DB27193B506D00B5C0D8 /* APDebugController.xib */, 124 | BB5CF62A1912DBD00052E10B /* APLogController.h */, 125 | BB5CF62B1912DBD00052E10B /* APLogController.m */, 126 | BB5CF62C1912DBD00052E10B /* APLogWindow.xib */, 127 | BB4E31041915943D00CC72EB /* APLiveCoding.h */, 128 | BB4E31051915943D00CC72EB /* APLiveCoding.m */, 129 | BB5CF62F1912DBD00052E10B /* APTextView.h */, 130 | BB5CF6301912DBD00052E10B /* APTextView.m */, 131 | ); 132 | path = Classes; 133 | sourceTree = ""; 134 | }; 135 | /* End PBXGroup section */ 136 | 137 | /* Begin PBXNativeTarget section */ 138 | 8D5B49AC048680CD000E48DA /* ApportablePlugin */ = { 139 | isa = PBXNativeTarget; 140 | buildConfigurationList = 1DEB913A08733D840010E9CD /* Build configuration list for PBXNativeTarget "ApportablePlugin" */; 141 | buildPhases = ( 142 | 8D5B49B1048680CD000E48DA /* Sources */, 143 | 8D5B49B3048680CD000E48DA /* Frameworks */, 144 | BB5251F8160A2EF700276EB3 /* Resources */, 145 | BB553A6D19167A020005E800 /* ShellScript */, 146 | ); 147 | buildRules = ( 148 | ); 149 | dependencies = ( 150 | ); 151 | name = ApportablePlugin; 152 | productInstallPath = "$(HOME)/Library/Bundles"; 153 | productName = QuietXcode; 154 | productReference = 8D5B49B6048680CD000E48DA /* ApportablePlugin.xcplugin */; 155 | productType = "com.apple.product-type.bundle"; 156 | }; 157 | /* End PBXNativeTarget section */ 158 | 159 | /* Begin PBXProject section */ 160 | 089C1669FE841209C02AAC07 /* Project object */ = { 161 | isa = PBXProject; 162 | attributes = { 163 | LastUpgradeCheck = 0440; 164 | }; 165 | buildConfigurationList = 1DEB913E08733D840010E9CD /* Build configuration list for PBXProject "ApportablePlugin" */; 166 | compatibilityVersion = "Xcode 3.2"; 167 | developmentRegion = English; 168 | hasScannedForEncodings = 1; 169 | knownRegions = ( 170 | English, 171 | Japanese, 172 | French, 173 | German, 174 | en, 175 | ); 176 | mainGroup = 089C166AFE841209C02AAC07 /* QuietXcode */; 177 | projectDirPath = ""; 178 | projectRoot = ""; 179 | targets = ( 180 | 8D5B49AC048680CD000E48DA /* ApportablePlugin */, 181 | ); 182 | }; 183 | /* End PBXProject section */ 184 | 185 | /* Begin PBXResourcesBuildPhase section */ 186 | BB5251F8160A2EF700276EB3 /* Resources */ = { 187 | isa = PBXResourcesBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | BB5CF6331912DBD00052E10B /* APConsoleWindow.xib in Resources */, 191 | BB9D656019194D9E00ECF4B3 /* play.png in Resources */, 192 | BBB0DB28193B506D00B5C0D8 /* APDebugController.xib in Resources */, 193 | BB5CF6351912DBD00052E10B /* APLogWindow.xib in Resources */, 194 | BB82F0CD1913D15F0015AE7A /* README.md in Resources */, 195 | BB26AE9F191FF6DF00702773 /* prepare.py in Resources */, 196 | BB9D655F19194D9E00ECF4B3 /* pause.png in Resources */, 197 | BB26AEA0191FF6E300702773 /* inject.py in Resources */, 198 | BBF5D8E31912DFCA0037CE2E /* APPluginMenuController.xib in Resources */, 199 | ); 200 | runOnlyForDeploymentPostprocessing = 0; 201 | }; 202 | /* End PBXResourcesBuildPhase section */ 203 | 204 | /* Begin PBXShellScriptBuildPhase section */ 205 | BB553A6D19167A020005E800 /* ShellScript */ = { 206 | isa = PBXShellScriptBuildPhase; 207 | buildActionMask = 2147483647; 208 | files = ( 209 | ); 210 | inputPaths = ( 211 | ); 212 | outputPaths = ( 213 | ); 214 | runOnlyForDeploymentPostprocessing = 0; 215 | shellPath = /bin/sh; 216 | shellScript = "rm -rf InjectionDemo/build\ncp -r Classes/APLiveCoding.* InjectionDemo \"$INSTALL_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH\"\n"; 217 | showEnvVarsInLog = 0; 218 | }; 219 | /* End PBXShellScriptBuildPhase section */ 220 | 221 | /* Begin PBXSourcesBuildPhase section */ 222 | 8D5B49B1048680CD000E48DA /* Sources */ = { 223 | isa = PBXSourcesBuildPhase; 224 | buildActionMask = 2147483647; 225 | files = ( 226 | BB5CF6371912DBD00052E10B /* APTextView.m in Sources */, 227 | BB5CF63A1912DCC50052E10B /* APPluginMenuController.m in Sources */, 228 | BB5CF6321912DBD00052E10B /* APConsoleController.m in Sources */, 229 | BBB0DB26193B505200B5C0D8 /* APDebugController.m in Sources */, 230 | BB5CF6341912DBD00052E10B /* APLogController.m in Sources */, 231 | ); 232 | runOnlyForDeploymentPostprocessing = 0; 233 | }; 234 | /* End PBXSourcesBuildPhase section */ 235 | 236 | /* Begin XCBuildConfiguration section */ 237 | 1DEB913B08733D840010E9CD /* Debug */ = { 238 | isa = XCBuildConfiguration; 239 | buildSettings = { 240 | ALWAYS_SEARCH_USER_PATHS = NO; 241 | CLANG_ENABLE_OBJC_ARC = YES; 242 | CODE_SIGN_ENTITLEMENTS = ""; 243 | CODE_SIGN_IDENTITY = ""; 244 | COMBINE_HIDPI_IMAGES = YES; 245 | COPY_PHASE_STRIP = NO; 246 | DEPLOYMENT_LOCATION = YES; 247 | DEPLOYMENT_POSTPROCESSING = YES; 248 | DSTROOT = "$(HOME)"; 249 | GCC_DYNAMIC_NO_PIC = NO; 250 | GCC_ENABLE_OBJC_GC = unsupported; 251 | GCC_MODEL_TUNING = G5; 252 | GCC_OPTIMIZATION_LEVEL = 0; 253 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 254 | INFOPLIST_FILE = Info.plist; 255 | INSTALL_PATH = "/Library/Application Support/Developer/Shared/Xcode/Plug-ins"; 256 | LD_RUNPATH_SEARCH_PATHS = /Developer; 257 | PRODUCT_NAME = ApportablePlugin; 258 | STRIP_INSTALLED_PRODUCT = NO; 259 | WRAPPER_EXTENSION = xcplugin; 260 | }; 261 | name = Debug; 262 | }; 263 | 1DEB913F08733D840010E9CD /* Debug */ = { 264 | isa = XCBuildConfiguration; 265 | buildSettings = { 266 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 267 | CURRENT_PROJECT_VERSION = 3.5; 268 | GCC_C_LANGUAGE_STANDARD = c99; 269 | GCC_OPTIMIZATION_LEVEL = 0; 270 | GCC_PREPROCESSOR_DEFINITIONS = DEBUG; 271 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 272 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 273 | GCC_WARN_UNUSED_VARIABLE = YES; 274 | INFOPLIST_PREPROCESSOR_DEFINITIONS = ""; 275 | INSTALL_PATH = "$(HOME)/Library/Application Support/Developer/Shared/Xcode/Plug-ins"; 276 | MACOSX_DEPLOYMENT_TARGET = 10.7; 277 | SDKROOT = macosx; 278 | }; 279 | name = Debug; 280 | }; 281 | /* End XCBuildConfiguration section */ 282 | 283 | /* Begin XCConfigurationList section */ 284 | 1DEB913A08733D840010E9CD /* Build configuration list for PBXNativeTarget "ApportablePlugin" */ = { 285 | isa = XCConfigurationList; 286 | buildConfigurations = ( 287 | 1DEB913B08733D840010E9CD /* Debug */, 288 | ); 289 | defaultConfigurationIsVisible = 0; 290 | defaultConfigurationName = Debug; 291 | }; 292 | 1DEB913E08733D840010E9CD /* Build configuration list for PBXProject "ApportablePlugin" */ = { 293 | isa = XCConfigurationList; 294 | buildConfigurations = ( 295 | 1DEB913F08733D840010E9CD /* Debug */, 296 | ); 297 | defaultConfigurationIsVisible = 0; 298 | defaultConfigurationName = Debug; 299 | }; 300 | /* End XCConfigurationList section */ 301 | }; 302 | rootObject = 089C1669FE841209C02AAC07 /* Project object */; 303 | } 304 | --------------------------------------------------------------------------------