On Device Console for iOS Developers
Xcode gives us a bunch of tools to keep the nasties at bay.
There are so many situations where you want to see same Xcode console log output while you are not actually debugging you application using Xcode.
Your tester reported one issue ( which is not easily reproducible ) . And you wanted to see the console output to resolve the issue.
You might have think lots of times :- ‘Wish i was able to see console output of application right their.
Lets make a control which will you show console output on device itself.
Resource:
There is a file in application directory which actually saves the every log output you see in Xcode console while debugging.
The smarter way is to simply read the file and show on device using some good user interface.
//
// AKSDeviceConsole.h
//
#import <Foundation/Foundation.h>
@interface AKSDeviceConsole : NSObject
+ (void)startService;
@end
//
// AKSDeviceConsole.m
//
#import “AKSDeviceConsole.h”
#import “AppDelegate.h”
#import <QuartzCore/QuartzCore.h>
#define AKS_LOG_FILE_PATH [[AKSDeviceConsole documentsDirectory] stringByAppendingPathComponent:@”ns.log”]
#define APPDELEGATE ((AppDelegate *)[[UIApplication sharedApplication] delegate])
@interface AKSDeviceConsole () {
UITextView *textView;
}
@end
@implementation AKSDeviceConsole
+ (id)sharedInstance {
static id __sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
__sharedInstance = [[AKSDeviceConsole alloc]init];
});
return __sharedInstance;
}
+ (NSMutableString *)documentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
}
– (id)init {
if (self = [super init]) {
[self initialSetup];
}
return self;
}
– (void)initialSetup {
[self resetLogData];
[self addGestureRecogniser];
}
+ (void)startService {
double delayInSeconds = 0.1;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
[AKSDeviceConsole sharedInstance];
});
}
– (void)resetLogData {
[NSFileManager.defaultManager removeItemAtPath:AKS_LOG_FILE_PATH error:nil];
freopen([AKS_LOG_FILE_PATH fileSystemRepresentation], “a”, stderr);
}
– (void)addGestureRecogniser {
UISwipeGestureRecognizer *recogniser = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(showConsole)];
[recogniser setDirection:UISwipeGestureRecognizerDirectionRight];
[APPDELEGATE.window addGestureRecognizer:recogniser];
}
– (void)showConsole {
if (textView == nil) {
CGRect bounds = [[UIScreen mainScreen] bounds];
CGRect viewRectTextView = CGRectMake(30, bounds.size.height – bounds.size.height / 3 – 60, bounds.size.width – 30, bounds.size.height / 3);
textView = [[UITextView alloc]initWithFrame:viewRectTextView];
[textView setBackgroundColor:[UIColor blackColor]];
[textView setFont:[UIFont systemFontOfSize:10]];
[textView setEditable:NO];
[textView setTextColor:[UIColor whiteColor]];
[[textView layer]setOpacity:0.6];
[APPDELEGATE.window addSubview:textView];
[APPDELEGATE.window bringSubviewToFront:textView];
UISwipeGestureRecognizer *recogniser = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(hideWithAnimation)];
[recogniser setDirection:UISwipeGestureRecognizerDirectionLeft];
[textView addGestureRecognizer:recogniser];
[self moveThisViewTowardsLeftToRight:textView duration:0.30];
[self setUpToGetLogData];
[self scrollToLast];
}
}
– (void)hideWithAnimation {
[self moveThisViewTowardsLeft:textView duration:0.30];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self hideConsole];
});
}
– (void)hideConsole {
[textView removeFromSuperview];
[NSNotificationCenter.defaultCenter removeObserver:self];
textView = nil;
}
– (void)scrollToLast {
NSRange txtOutputRange;
txtOutputRange.location = textView.text.length;
txtOutputRange.length = 0;
textView.editable = YES;
[textView scrollRangeToVisible:txtOutputRange];
[textView setSelectedRange:txtOutputRange];
textView.editable = NO;
}
– (void)setUpToGetLogData {
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:AKS_LOG_FILE_PATH];
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(getData:) name:@”NSFileHandleReadCompletionNotification” object:fileHandle];
[fileHandle readInBackgroundAndNotify];
}
– (void)getData:(NSNotification *)notification {
NSData *data = notification.userInfo[NSFileHandleNotificationDataItem];
if (data.length) {
NSString *string = [NSString.alloc initWithData:data encoding:NSUTF8StringEncoding];
textView.editable = YES;
textView.text = [textView.text stringByAppendingString:string];
textView.editable = NO;
double delayInSeconds = 1.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
[self scrollToLast];
});
[notification.object readInBackgroundAndNotify];
}
else {
[self performSelector:@selector(refreshLog:) withObject:notification afterDelay:1.0];
}
}
– (void)refreshLog:(NSNotification *)notification {
[notification.object readInBackgroundAndNotify];
}
– (void)moveThisViewTowardsLeft:(UIView *)view duration:(float)dur; {
[UIView animateWithDuration:dur animations: ^{
[view setFrame:CGRectMake(view.frame.origin.x – [[UIScreen mainScreen]bounds].size.width, view.frame.origin.y, view.frame.size.width, view.frame.size.height)];
} completion: ^(BOOL finished) {}];
}
– (void)moveThisViewTowardsLeftToRight:(UIView *)view duration:(float)dur; {
CGRect original = [view frame];
[view setFrame:CGRectMake(view.frame.origin.x – [[UIScreen mainScreen]bounds].size.width, view.frame.origin.y, view.frame.size.width, view.frame.size.height)];
[UIView animateWithDuration:dur animations: ^{
[view setFrame:original];
} completion: ^(BOOL finished) {}];
}
@end
The above class is a complete control to show/hide on device console window on top of the application screen dynamically.
simply drop the above class in your project.
And initiate on device console like
– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
[AKSDeviceConsole startService];
return YES;
}
How to use show and hide console
Swipe left and right to hide and show the console
The Complete Demo Example Project is available here
On CocoaControls
https://www.cocoacontrols.com/controls/aksdeviceconsole
On Github
https://github.com/aryansbtloe/AksDeviceConsole
By: Vipin Jain
About Vipin Jain
Vipin Jain (CEO / Founder of Konstant Infosolutions Pvt. Ltd.) Mobile App Provider (A Division of Konstant Infosolutions Pvt. Ltd.) has an exceptional team of highly experienced & dedicated mobile application and mobile website developers, business analysts and service personnels, effectively translating your business goals into a technical specification and online strategy. Read More View all posts by Vipin JainRecent Posts
- Airbnb Alternatives: 7 Just as Good Vacation Rental Apps
- React Native vs Xamarin vs Ionic: Best Hybrid App Development Frameworks for 2019
- Best Programming Language for Mobile App Development
- Want You Ride-Sharing App to Succeed? Consider These 4 Strategies from Juno
- How Do Apps Make Money? The Best Strategies and Use Cases
Archives
- May 2022
- June 2019
- May 2019
- April 2019
- March 2019
- February 2019
- December 2018
- January 2018
- December 2017
- October 2017
- September 2017
- July 2017
- June 2017
- May 2017
- April 2017
- March 2015
- November 2014
- October 2014
- December 2013
- November 2013
- October 2013
- August 2013
- July 2013
- June 2013
- May 2013
- April 2013
- March 2013
- January 2013
- December 2012
- November 2012
- July 2012
- June 2012
- May 2012
- April 2012
- March 2012
- February 2012
- January 2012
- December 2011
- November 2011
- October 2011
- August 2011
- May 2011




