Wednesday, 19 November 2014

How to start developing apps for Apple Watch using WatchKit framework iOS 8.2 and Xcode 6.2

It was a wonderful day yesterday (Nov-18th, 2014) for iOS developers, finally Apple  released Xcode 6.2 Beta with WatchKit framework to start developing apps for Apple Watches. It started a new chapter in iOS developers  life to play with Watchkit framework and make relationship with Apple watches.

I am not sure about What the NDA restrictions are, but I am just having thing on the basis of publicly information the  Apple WatchKit
But its not so limited information, its too much to learn with Beta release.

Software and tools required to start developing apps for Apple Watch using WatchKit framework are.

1- Xcode 6.2 or latter
2- Mac OSx 10.10
3- iOS 8.2 or latter

Lets first go through some basic but interesting things about Apple Watch Architecture and Watchkit Layout.

* iPhone Device:  It works like a "Model" and "Controller" of the  app. iPhone Device contains all the code of the application and responds to all the events like app launch, button taps etc.

* Apple Watch: It works like a "View" of the  app. All the Static images and Storyboard are contains in it. It is an user interface of the app. It process user inputs but did not run any code.

Communication between Apple Watch and  iPhone get automatically. Wow interesting! WatchKit SDK handles this communication via Bluetooth behind the scenes.
One issue for developers is that Animations are not supported in WatcKit. It means Developers will try for third party API (if any) or They will use set of .GIF images to achieve animations.

Two new words are seen to represent Watchkit, Glances and Notifications.

1-Glances: Provides a Quick overview of the contents within app

2-Notifications: Let us receive notifications on our watch.


Sunday, 9 November 2014

How to Scan Barcode using iOS native framework

Prior to iOS 7, It was a big problem for iOS developer to add a native QR code scanner. So some third party code library were used to achieve barcode scanning. But iOS 7 brings a bunch of new features. The AVFoundation framework is  one of them where some new API/classes are added, as a result AVFoundation provided the ability to discover and read bar codes in real time.

In this tutorial we are going to scan a QR Code, its known as Quick Response Code. QR Code is 2D barcode. Its design can have horizontal and vertical lines. So you can scan 1D (vertical lines) and 2D (Vertical and Horizontal lines).

What can be store in QR code ?
QR Code can contain information of like web URL, Phone number, SMS text and other Simple text.


Lets start how to Implement QR Code Scanning with Native iOS framework.

1- Open Xcode and create a new project  (I pick single view application  ), name it "BarcodeScanner".

2-Open Storyboard and Create a UIbutton to Start/Stop scanning, a UILabel to print scanning status/scanned information, And a UIView inside that a camera will be open to scan QR code.


QR Code scan and read using native iOS framework

3- Open ViewController.h and  define some properties

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>

@interface ViewController : UIViewController<AVCaptureMetadataOutputObjectsDelegate>

@property (nonatomic, strong) AVCaptureSession *captureSession;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *videoPreviewLayer;
@property(nonatomic,assign) BOOL IsScanning;

@property(weak, nonatomic)IBOutlet UILabel *lblScanStatus_info;
@property(weak, nonatomic)IBOutlet UIButton *btnStartStop;
@property(weak, nonatomic)IBOutlet UIView *vwCameraPreview;

-(IBAction)StartStop_Scan:(id)sender;
@end



4- Connect IBOutlet from starboard, Connect "StartStop_Scan" method to Button.
Open ViewController.m
Define two private method one for Start Scan and Second one for Stop scan

@interface ViewController ()
-(void)StartScanning;
-(void)StopScanning;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    _IsScanning = NO; //
    
}

#pragma mark IBAction

-(IBAction)StartStop_Scan:(id)sender
{
    NSLog(@"Inside startstopmethod");
    //If start button  pressed
    if(!_IsScanning)
    {
        [self StartScanning];
        
    }
    ////If Stop button  pressed
    else
    {
        [self StopScanning];
        
    }
    
    //set the flag opposit to earlier ;
    _IsScanning = !_IsScanning;
}

Don't forget to check camera support in device, Simulator don't support camera so we need a device to run this tutorial.


-(void)StartScanning
{
    AVCaptureDevice *captureDevice = nil;
    AVCaptureDeviceInput *input = nil;
    //Check for device camera existance
    NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    if ( [videoDevices count] > 0 ) // This device has one or more cameras
    {
        NSError *error;
        captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        
        // Get an instance of the AVCaptureDeviceInput class
        input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
        
        if (!input) {
            // If any error occurs, simply log the description
            NSLog(@"error desc:%@", [error localizedDescription]);
            
        }
        else
        {
            // init the captureSession .
            _captureSession = [[AVCaptureSession alloc] init];
            // Set  input device at the capture session.
            [_captureSession addInput:input];
            
            
            // Initialization of a AVCaptureMetadataOutput object and set it to output sessioncapture
            AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
            [_captureSession addOutput:captureMetadataOutput];
            
            // make a serial dispatch queue.
            dispatch_queue_t dispatchQueue;
            dispatchQueue = dispatch_queue_create("QRCodeScanQueue", NULL);
            [captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
            [captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];
            
            //  video preview layer and adding at subview _vwCameraPreview
            _videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
            [_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
            [_videoPreviewLayer setFrame:_vwCameraPreview.layer.bounds];
            [_vwCameraPreview.layer addSublayer:_videoPreviewLayer];
            
            // Start video capturing.
            [_captureSession startRunning];
            
            [_btnStartStop setTitle:@"Stop Scan" forState:UIControlStateNormal];
            [_lblScanStatus_info setText:@"Scanning for QR Code:-----"];

        }
    }
    else
    {
        NSLog(@"Camera is not supported here");
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert" message:@"Current device does not supporting camera " delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
        
        [alert show];
        
    }
    
}

-(void)StopScanning
{
    // Stop video capture
    [_captureSession stopRunning];
    _captureSession = nil;
    
    // Remove video preview layer.
    [_videoPreviewLayer removeFromSuperlayer];
    
    [_btnStartStop setTitle:@"Start Scan" forState:UIControlStateNormal];
    [_lblScanStatus_info setText:@"QR Code Scan is not started"];
}

#pragma mark Implememntaion of AVCaptureMetadataOutputObjectsDelegate method

-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
    
    if (metadataObjects != nil && [metadataObjects count] > 0) {
        // Get the metadata object.
        AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
        //Check QR type meta data object
        if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {
            // If the found metadata is equal to the QR code metadata then update the label status info text,
            
            // Proecees of main thread done.
            [_lblScanStatus_info performSelectorOnMainThread:@selector(setText:) withObject:[metadataObj stringValue] waitUntilDone:NO];
            //and stop reading
            [self performSelectorOnMainThread:@selector(StopScanning) withObject:nil waitUntilDone:NO];
            
            [_btnStartStop performSelectorOnMainThread:@selector(setTitle:) withObject:@"Start Scan" waitUntilDone:NO];
            
            _IsScanning = NO;
            
        }
    }
}

To test QR code scan you may find some images from Google and or use the image shown above for sample QR code.

Hope you will enjoyed this code. If you have any concern please share your comments.

Sunday, 2 November 2014

How to fix CLLocationManager location updates issue in iOS 8

It was  time consuming issue for me to  fix CLLocationManager location update issue in iOS 8.x, I was too much worried, why my code is not working in iOS 8 neither asking for user permission nor the location update delegate. 

CLLocationManager fails to work with  [self.locationManager startUpdatingLocation]. CLLocationManager not working for updating location updates. Its neither giving any error nor warning so it is more complex to figure out why this is not working.
Even Application did not ask for location related permission. So you might get irritate, don’t worry here the solution.

What are extra updates for iOS 8:
There are two more things need to be add to working with location.
1- Add one or both below keys to (app-name)info .plist file:

* NSLocationAlwaysUsageDescription
* NSLocationWhenInUseUsageDescription

Above keys take a string as description of why your app need location services. You may enter a string like “To Find out your location”
Note: iOS will not ask an user for permission to use their location until you have given a reason as why you are requesting it.

2- Request authorization for related location method, i.e WhenInUSe or Always. Use one of below method calls.

[self.locationManager requestWhenInUseAuthorization];
[self.locationManager requestAlwaysAuthorization];

WhenInUseAuthorization:  It allows the application to get location updates when the application is in foreground state and not in other state.
requestAlwaysAuthorization: It allows the application to get location updates in both when the application  is in the foreground and or in the background.
Below is the sample code for help.

Before using this code make sure you already added NSLocationWhenInUseUsageDescription in the  (app-name)info .plist  file.

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    // Check for iOS 8 Vs earlier version like iOS7.Otherwise code will
   // crash on ios 7
    if ([self.locationManager respondsToSelector:@selector
                       (requestWhenInUseAuthorization)]) {
        [self.locationManager requestWhenInUseAuthorization];
    }
    [self.locationManager startUpdatingLocation];
}

// CLLocationManager Delegate Methods
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:
(NSArray *)locations
{
    NSLog(@"location info object=%@", [locations lastObject]);
}
 
 
I hope You will enjoyed this post and if you any suggestion or feedback
 your most welcome

Thursday, 9 October 2014

Making ad hoc build from command line without signing to developer account in Xcode 6 and iOS 8

It was the first problem I face during the use of xcode 6 first time, how can i share .ipa to my clients for demo purpose? I was unable to share an .ipa without signing Apple developer account. Xcode 6 was asking to sign with Developer account to export an .ipa file. Although I had the developer account details but it was the challenge how to make a adhoc build  without signing developer account.
After lots of Googling and consulting with other friends, I found  an alternate solution to achieve ad-hoc  build without signing developer account, solution is  command line/Terminal, you can create a adhoc build using command line tool and or a terminal on mac system.

Let me share the simplest way to create adhoc build using command line tool.

I note down 3 things to create quickest Xcode 6 build. So get ready for these 3 things before opening Terminal.

1- Project path: it will be required in terminal command as a parameter.

2- scheme name: it will be required in terminal command as a parameter.

3- Provisioning Profile name: it will be required in terminal command as a parameter.

Finding scheme name: Default scheme name is the project name but once verify. scheme name displays next to RUN icon in Xcode that is used to execute the app.

Finding Provisioning Profile name: This parameter value will be exact same as it display in Xcode; Provisioning Profile list under Code Signing Identity in build settings section of Xcode 6.

There are three steps two create build from command line tool

1- Clean project
2- Make Archive
3- Export to .ipa file

 Lets start with first. To clean project we will execute below command in Terminal  and or command line tool of mac system.
xcodebuild clean -project <projectname.xcodeproj> -configuration Release -alltargets

here  <projectname.xcodeproj> will be replace with the project path with .xcodeproj extension 

For example on my system's terminal
ajsharma$
xcodebuild clean -project /Users/ajsharma/Documents/iPad/testApp/testApp.xcodeproj -configuration Release -alltargets

Terminal will show you some process and updates and show you success message regarding project clean.
Lets go for next step to Make an archive using below command

xcodebuild archive -project <projectname.xcodeproj> -scheme <schemename> -archivePath <projectname.xcarchive>

here
<projectname.xcodeproj> will be replace with the project path with .xcodeproj extension 
<schemename> will be replace with the shceme name of the project as I discussed above.

<projectname.xcarchive> will be replace with the project path with .xcarchive extension


For example on my system's terminal
ajsharma$
xcodebuild archive -project  /Users/ajsharma/Documents/iPad/testApp/testApp.xcodeproj -scheme testApp -archivePath /Users/ajsharma/Documents/iPad/testApp/testApp.xcarchive

I used same path for as project Path for archivePath you may change it. So an archive file will be create at same path as project path.

@workspace:
Sorry I forgot to mention important command for those who have configured their projects under a WorkSpace or using pods in their projects.
For those people there would be slightly change in  command to make an archive. But I was not using workspace.

xcodebuild -workspace <projectname.xcworkspace> -scheme <schemename> archive -archivePath <projectname.xcarchive

 here;
<projectname.xcworkspace > will be replace with the project path with .xcworkspace extension.
<schemename> will be replace with the shceme name of the project as I discussed above.

<projectname.xcarchive> will be replace with the project path with .xcarchive extension

Lets go for  final step to Export to .ipa  using below command

xcodebuild -exportArchive -archivePath <projectname.xcarchive> -exportPath <projectname> -exportFormat ipa -exportProvisioningProfile “Provisioning Profile Name”

here
<projectname.xcarchive> will be replace with the project path with .xcarchive extension
<projectname>  will be replace with the project path with out .xcarchive or .xcodeproj extension
“Provisioning Profile Name”  will be replace with the Provisioning Profile Name  as I discussed above.

For example on my system's terminal
ajsharma$
xcodebuild -exportArchive -archivePath /Users/ajsharma/Documents/iPad/testApp/testApp.xcarchive -exportPath /Users/ajsharma/Documents/iPad/testApp/testApp -exportFormat ipa -exportProvisioningProfile TestProvision

If everything works fine the final result screen would be some thing like below text as per my project path.

Moving exported product to '/Users/ajsharma/Documents/iPad/testApp/testApp.ipa'
** EXPORT SUCCEEDED **


You can get the .ipa file from the above path as per your project path at your system and share with your client.

If you have any other best way to create adhoc build without using developer account, please share your comments.


Wednesday, 8 October 2014

2 steps to use UITableViewCell separatorinset in ios 8 and setLayoutMargins in iOS 8

During porting from iOS 7.x objective-C based code in to iOS 8.x objective-C, I noticed that UITableviewCell separator disturbed from left and right side. Separator line got margin from left and right. It was fixed in iOS 7.x code using separator "inset" to 0. but it become default 15 in iOS 8 storyboard. even setting it  to zero (0) it didn't worked.

Actually in iOS 8 layoutMargins a new property is introduced. So problem comes in mind;  How to use layoutMargins on the cells and tableview in iOS 8?
it is missing in earlier version. so we need to put a check also to its availability.


Two fix it in iOS 8.x, need to use below 2 steps

1- For Cell

-(void)tableView:(UITableView *)tableView willDisplayCell:
(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
        [cell setSeparatorInset:UIEdgeInsetsZero];
    }

    if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
        [cell setLayoutMargins:UIEdgeInsetsZero];
    }
}

2- For Tableview

-(void)viewDidLayoutSubviews
{
    if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) 
    {
        [self.tableView setSeparatorInset:UIEdgeInsetsZero];
    }

    if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) 
    {
        [self.tableView setLayoutMargins:UIEdgeInsetsZero];
    }
}

Both steps need to be follow to achieve Separatorinset in iOS 8


This is the best way to use UITableViewCell separatorinset in ios 8 and  setLayoutMargins in iOS 8.

If you have some better way please share your valuable ideas in comment section.



Monday, 6 October 2014

How to change UISegmentedControl text font and color

UISegmentedControl is mainly used to toggle between two screen or functionality from a common screen. but some times it requires to change the font size of the UISegmentedControl text. Interface builder is not providing the option to change the text font size.

Let me share the way how to change UISegmentedControl text font size and text color.

Create a new viewcontroller in your project or may create a new project if you dont want to modify your existing project for safety point of view.

I am creating UIsegmented control using code but if you using IBOutlet you can go with that also.

in .h file

@interface ViewController : UIViewController

@property (strong, nonatomic)  UISegmentedControl *segment1;

@property (strong, nonatomic)  UISegmentedControl *segment2;
@end

in .m file

 - (void)viewDidLoad
{
    [super viewDidLoad];
   
     NSMutableArray *segtitleArr=[[NSMutableArray alloc]initWithObjects:@"First1",@"Second2", nil];
    _segment1 = [[UISegmentedControl alloc]initWithItems:segtitleArr];
    _segment1.frame = CGRectMake(30, 50, 252, 29);
   
    NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                [UIFont fontWithName:@"Helvetica" size:17], NSFontAttributeName,
                                [UIColor redColor], NSForegroundColorAttributeName, nil];

  
    [_segment setTitleTextAttributes:attributes forState:UIControlStateNormal];
  
    [self.view addSubview:_segment];



//creating second segment.
  
    NSMutableArray *segtitleArr2=[[NSMutableArray alloc]initWithObjects:@"Third3",@"Fourth"4, nil];
    _segment2 = [[UISegmentedControl alloc]initWithItems:segtitleArr2];
    _segment2.frame = CGRectMake(30, 152, 252, 29);
    _segment2.tintColor = [UIColor colorWithRed: 8/255.0 green:83/255.0 blue:131/255.0 alpha:1.0];
  
    NSDictionary *attributes2 = [NSDictionary dictionaryWithObjectsAndKeys:
                                [UIFont fontWithName:@"Helvetica" size:10], NSFontAttributeName,
                                [UIColor orangeColor], NSForegroundColorAttributeName, nil];

  
    [_segment2 setTitleTextAttributes:attributes2 forState:UIControlStateNormal];
  
    [self.view addSubview:_segment2];




Best way to change UISegmentedControl text colr and  size



Above code will show you two segment control in different text size and font color and selected segmented color change using tint color property.
In both UISegmented control one thing is common that is a NSDictionary having objects of Font/Text and color these you can change as per your requirement.

If you find another best way to change UISegmentedControl  text  size and color, Please share using your comments below.

 

  
}

Friday, 3 October 2014