Thursday, 8 December 2016

Get Serial Number of Device

Get Serial Number of Device



Write Following Code in ViewController.m :-

#import <dlfcn.h>
#import <mach/port.h>
#import <mach/kern_return.h>





- (void)viewDidLoad {
    [super viewDidLoad];
    

    NSString *str = [self serialNumber];

    NSLog(@"Serial Number : %@"str) ;
  
}


- (NSString *) serialNumber
{
    NSString *serialNumber = nil;
    
    void *IOKit = dlopen("/System/Library/Frameworks/IOKit.framework/IOKit", RTLD_NOW);
    if (IOKit)
    {
        mach_port_t *kIOMasterPortDefault = dlsym(IOKit, "kIOMasterPortDefault");
        CFMutableDictionaryRef (*IOServiceMatching)(const char *name) = dlsym(IOKit, "IOServiceMatching");
        mach_port_t (*IOServiceGetMatchingService)(mach_port_t masterPort, CFDictionaryRef matching) = dlsym(IOKit, "IOServiceGetMatchingService");
        CFTypeRef (*IORegistryEntryCreateCFProperty)(mach_port_t entry, CFStringRef key, CFAllocatorRef allocator, uint32_t options) = dlsym(IOKit, "IORegistryEntryCreateCFProperty");
        kern_return_t (*IOObjectRelease)(mach_port_t object) = dlsym(IOKit, "IOObjectRelease");
        
        if (kIOMasterPortDefault && IOServiceGetMatchingService && IORegistryEntryCreateCFProperty && IOObjectRelease)
        {
            mach_port_t platformExpertDevice = IOServiceGetMatchingService(*kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
            if (platformExpertDevice)
            {
                CFTypeRef platformSerialNumber = IORegistryEntryCreateCFProperty(platformExpertDevice, CFSTR("IOPlatformSerialNumber"), kCFAllocatorDefault, 0);
                if (platformSerialNumber && CFGetTypeID(platformSerialNumber) == CFStringGetTypeID())
                {
                    serialNumber = [NSString stringWithString:(__bridge NSString *)platformSerialNumber];
                    CFRelease(platformSerialNumber);
                }
                IOObjectRelease(platformExpertDevice);
            }
        }
        dlclose(IOKit);
    }
    
    return serialNumber;
}





Count Last Seen Using Date

Count Last Seen Using Date



Write Following Code in ViewController.m :-


- (void)viewDidLoad {
    [super viewDidLoad];
   
    //----------------- Days Count
    
    NSLog(@"Last Seen : %@", [self relativeDateStringForDate:[self StringToFormatedDate:@"2016-12-08 06:29:25"]]) ;

}


-(NSDate *)StringToFormatedDate:(NSString *)dateStr
{
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSDate *date = [dateFormatter dateFromString:dateStr];
    return date;
}


- (NSString *)relativeDateStringForDate:(NSDate *)date
{
    
    NSCalendarUnit units = NSDayCalendarUnit | NSWeekOfYearCalendarUnit |
    NSMonthCalendarUnit | NSYearCalendarUnit ;
    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDateComponents *components1 = [cal components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:[NSDate date]];
    NSDate *today = [cal dateFromComponents:components1];
    
    components1 = [cal components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:date];
    NSDate *thatdate = [cal dateFromComponents:components1];
    
    // if `date` is before "now" (i.e. in the past) then the components will be positive
    NSDateComponents *components = [[NSCalendar currentCalendar] components:units
                                                                   fromDate:thatdate
                                                                     toDate:today
                                                                    options:0];
    
    if (components.year > 0) {
        return [NSString stringWithFormat:@"%ld years ago", (long)components.year];
    } else if (components.month > 0) {
        return [NSString stringWithFormat:@"%ld months ago", (long)components.month];
    } else if (components.weekOfYear > 0) {
        return [NSString stringWithFormat:@"%ld weeks ago", (long)components.weekOfYear];
    } else if (components.day > 0) {
        if (components.day > 1) {
            return [NSString stringWithFormat:@"%ld days ago", (long)components.day];
        } else {
            return @"Yesterday";
        }
    } else {
        return @"Today";
    }
}

Wednesday, 7 December 2016

Unique Identifiers

The Developer’s Guide to Unique Identifiers


We had been warned that uniqueIdentifier was going away, and now Apple is giving us not just one but two alternatives to use. But which one should you use and when is it appropriate to choose one over the other? The documentation doesn’t answer these questions and it is left up to you to decide what is best for your applications’ purposes.
I am going to outline each of the iOS supported and deprecated unique identifier methods to explain what they do in hopes of arming you with the knowledge you need to make the right decisions.

CFUUID

Starting with the oldest, CFUUID has been around since iOS 2.0. It is part of the CoreFoundation package and therefore C style API. CFUUIDCreate is the method you use to create the CFUUIDRef and you can get an NSString representation of the created CFUUIDRef like this.

CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault);

NSString *cfuuidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid));


The thing to know about the CFUUID is that it is not persisted at all. Every time you call CFUUIDCreate the system will return to you a brand new unique identifier. If you want to persist this identifier you will need to do that yourself using NSUserDefaults, Keychain, Pasteboard or some other means.
Example: 68753A44-4D6F-1226-9C60-0050E4C00067

NSUUID

This is the new younger cousin to CFUUID. NSUUID just popped up in iOS 6. It is pretty much exactly the same as CFUUID except it has a nice, modern Objective-C interface. + (id)UUID is the class method you call to get a UUID and you can get an NSString representation of that UUID object like this.
NSString *uuid = [[NSUUID UUID] UUIDString];
Just like the CFUUID, this is not persisted at all and you will get a new unique identifier each time you call it. You must do all the persisting yourself. I noticed an interesting thing while reading the docs on NSUUID. The example ID that Apple gives for both CFUUID and NSUUID are the exact same identifier.
Example: 68753A44-4D6F-1226-9C60-0050E4C00067

Advertiser Identifier

Another new method as of iOS 6, advertisingIdentifier is part of the new AdSupport.framework. The ASIdentifierManager singleton exposes the method advertisingIdentifier and calling that returns an instance of the NSUUID class mentioned above.
NSString *adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
Unlike the direct CFUUID and NSUUID calls, the advertisingIdentifier is persisted by the system. However, even though it is persisted there are a few scenarios in which it will get regenerated. If the user does a full system reset (Settings.app -> General -> Reset -> Reset All Content and Settings) the advertisingIdentifier will get regenerated. If the user explicitly resets it (Settings.app -> General -> About -> Advertising -> Reset Advertising Identifier) it will get regenerated. There is one caveat to the Advertising Reset. If your app is running in the background while the user does a “Reset Advertising Identifier” and then returns to your app, the advertisingIdentifier is not immediately reset the next time you call it. You must terminate your app and then re-launch it to get the reset advertisingIdentifier. My guess is that this is because ASIdentifierManager is exposed as a singleton.
Another option available to users is to “Limit Ad Tracking”. As our own Nick Arnott has already pointed out, turning this option on does nothing to actually limit your access to the advertisingIdentifier. It is simply a boolean flag that you are supposed to respect when sending the advertisingIdentifier to any servers.
Example: 1E2DFA89-496A-47FD-9941-DF1FC4E6484A

Identifier for Vendor (IDFV)

This call was also added in iOS 6, but it was added as a new method on the existing UIDevice class. Just like advertisingIdentifier, it returns an NSUUID object.
NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
The documentation for the identifierForVendor says this.
The value of this property is the same for apps that come from the same vendor running on the same device. A different value is returned for apps on the same device that come from different vendors, and for apps on different devices regardless of vendor.
The question I had after reading that was, “what’s a vendor?” My first thought was that a vendor was defined as an Apple Developer Account. That turned out to be dead wrong. Next I thought it might it have to do with the AppIdentifierPrefix; similar to how Keychain Access can be shared between apps. Also dead wrong. It turns out to be very simple. A Vendor is defined by the first two parts of the reverse DNS formatted CFBundleIdentifier. For example com.doubleencore.app1 and com.doubleencore.app2 would be able to get the same identifierForVendor since they share the same com.doubleencore part of the CFBundleIdentifier. But com.massivelyoverrated or even net.doubleencore would get a completely different identifierForVendor.
The other thing to point out here is that if a user uninstalls all of the apps from a vendor and then re-installs them, the identifierForVendor will be reset.
Example: 599F9C00-92DC-4B5C-9464-7971F01F8370

UDID

The old tried and true but deprecated in iOS 5. You know it, you love it but don’t even think of using it again because it is going away. At least it is for apps that will be submitted to the App Store. It remains to be seen if uniqueIdentifier will be turned into a private method or completely removed in a future iOS version. It is still needed for developers to provision devices in the iOS Developer Portal. And if you are distributing Enterprise signed applications it can also be very handy.
NSString *udid = [[UIDevice currentDevice] uniqueIdentifier];
Example: bb4d786633053a0b9c0da20d54ea7e38e8776da4

OpenUDID

Back when iOS 5 was released and uniqueIdentifier became deprecated there was a rush to find an alternative to the UDID that was not controlled by Apple. It seems that OpenUDID is the most widely used open source UDID alternative. OpenUDID is super simple to implement in your project and is supported by a slew of advertising providers.
NSString *openUDID = [OpenUDID value];
OpenUDID uses a very clever way to persist the identifier across applications. It uses specially named Pasteboards to store the identifier. This way, other apps that also use OpenUDID know where to go look and can grab the already generated identifier instead of generating a new one.
It has been mentioned that Apple will start to enforce the use of either the advertisingIdentifier or the identifierForVendor in the future. If this is the case, even though OpenUDID might seem like a good option now, you might have to transition to one of the Apple approved calls anyway.
Example: 0d943976b24c85900c764dd9f75ce054dc5986ff

Decisions

I hope I have presented you with enough information to help you make an informed decision about which unique identifier is right for your app. I have created a small unique identifier test app that you can run and view the output of all of the above mentioned calls. And below you will find a couple of tables that outline the calls, their iOS availability and when you can expect the identifier to get reset.
* The app must be restarted in order to see the change.
** All apps from that vendor must be deleted in order to change the value.

Wednesday, 23 November 2016

Application Call via Custom URL Scheme

Application Call via Custom URL Scheme

The Complete Tutorial on iOS/iPhone Custom URL Schemes







NoteSince the introduction of custom URL schemes, this post has consistently been the top read content on the blog. Although much is the same, there are a few nuances that have changed. This is a re-write of the original post, updated for the latest iOS and Xcode versions.
One of the coolest features of the iPhone/iOS SDK is an application’s ability to “bind” itself to a custom URL scheme and for that scheme to be used to launch the application from either a browser or from another application.

Registering a Custom URL Scheme

The first step is to create a custom URL scheme – start by locating and clicking on the project info.plist in the Xcode Project Navigator. With the plist displayed in the right pane, right click on the list and select Add Row:
From the list presented scroll down and select URL types.
iOS Custom URL Scheme
Open the directional arrow and you’ll see Item 0, a dictionary entry. Expand Item 0 and you will see URL Identifier, a string object. This string is the name for the custom URL scheme you are defining. It’s recommended to ensure uniqueness of the name that you reverse domain name such as com.yourCompany.yourApp.
urlScheme2a
Tap on Item 0 and add a new row, select URL Schemes from the drop-down and tap Enter to complete the row insert.
iOS Custom URL Scheme
Notice URL Schemes is an array, allowing multiple URL schemes to be defined for an application.
iOS Custom URL Scheme
Expand the array and tap on Item 0. This is where you will define the name for the custom URL scheme. Enter just the name, do not append :// – for instance, if you enter iOSDevApp, your custom url will be iOSDevApp://
iOS Custom URL Scheme
Here is how the complete definition looks at this point:
iOS Custom URL Scheme
Although I appreciate Xcode’s intention when using descriptive names, I find it helpful to see the actual keys created. Here’s a handy trick, right-click on the plist and select Show Raw Keys/Values, the output will look as follows:
iOS Custom URL Scheme
There’s another output format that also has merit, XML, as it’s much easier to see the structure of the dictionary and the nested array and its entries. Tap the plist and this time choose Open As – Source Code:
iPhone Custom URL Scheme

Calling Custom URL Scheme from Safari

With the URL scheme defined, we can run a quick test to verify the app can be called as expected using the URL. Before we do that, I’ll create a barebones UI so we can identify the app with the custom URL. The app contains nothing more than a UILabel with the text “App With Custom URL.” 
iOS App with Custom URL
Using the simulator, here’s how to call the app:
– Run the application from within Xcode
– Once installed, the custom URL scheme will now be registered
– Close the app via the Hardware menu in simulator and choose Home
– Start Safari
– Enter the URL scheme defined previously in the browser address bar (see below)
Call Custom URL Scheme from Safari
At this point Safari will close and the app will be brought to the foreground. Congratulations, you’ve just called an iPhone application using a custom URL scheme!

Calling Custom URL Scheme from Another iPhone App

Let’s take a look at how to call the custom URL scheme from another iPhone application. Again, I’ve created a very simple iPhone application with nothing more than a UILabel and a UIButton – the former shows a message that this is the app that will call another app via a custom URL scheme, the button starts that process. 
iPhone app that call Custom URL Scheme
The code inside the buttonPressed manages the URL processing:
- (void)buttonPressed:(UIButton *)button
{
  NSString *customURL = @"iOSDevTips://";
  if ([[UIApplication sharedApplication]
    canOpenURL:[NSURL URLWithString:customURL]])
  {
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:customURL]];
  }
  else
  {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"URL error"
                          message:[NSString stringWithFormat:
                            @"No custom URL defined for %@", customURL]
                          delegate:self cancelButtonTitle:@"Ok"
                          otherButtonTitles:nil];
    [alert show];
  }    
}

Line 5 we check to see if the custom URL is defined, and if so, use the shared application instance to open the URL (line 8). The openURL: method starts the application and passes the URL into the app. The current application is exited during this process.

Passing Parameters To App Via Custom URL Scheme

Chances are you’ll need to pass parameters into the application with the custom URL definition. Let’s look at how we can do this with.
The NSURL class which is the basis for calling from one app to another conforms to the (Relative Uniform Resource Locators). Therefore the same URL formatting you may be familiar with for web-based content will apply here as well.
In the application with the custom URL scheme, the app delegate must implement the method with the signature below:

- (BOOL)application:(UIApplication *)app
            openURL:(NSURL *)url
            options:(NSDictionary *)options


The trick to passing in parameters from one app to another is via the URL. For example, assume we are using the following custom URL scheme and want to pass in a value for a ‘token’ and a flag indicating registration state, we could create URL as follows:
NSString *customURL = @"iOSDevTips://?token=123abct&registered=1";



As in web development, the string ?token=123abct&registered=1 is known as the query string.
Inside the app delegate of the app being called (the app with the custom URL), the code to retrieve the parameters would be as follows:

****Write Code in Appdelegate



// Declare

@property (nonatomic, strong) NSURL *launchedURL;


// Write in didFinishLaunchingWithOptions Method

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{
    // Override point for customization after application launch.
    
    self.launchedURL = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey]; 

    NSLog(@"%@"self.launchedURL);

    return YES;
}
    
   
- (BOOL)application:(UIApplication *)app
            openURL:(NSURL *)url
            options:(NSDictionary *)options {
    
    if ([[url scheme] isEqualToString:@"siaevents"])
    {
        NSLog(@"url recieved: %@", url);
        NSLog(@"query string: %@", [url query]);
        NSLog(@"host: %@", [url host]);
        NSLog(@"url path: %@", [url path]);
        NSDictionary *dict = [self parseQueryString:[url query]];
        NSLog(@"query dict: %@", dict);

        NSURL *openUrl = url;
        
        if (!openUrl)
        {
            return NO;
        }

        return [self openLink:openUrl];
        
    }
}

- (NSDictionary *)parseQueryString:(NSString *)query {
    NSMutableDictionary *dict = [[[NSMutableDictionary alloc] initWithCapacity:6] autorelease];
    NSArray *pairs = [query componentsSeparatedByString:@"&"];
    
    for (NSString *pair in pairs) {
        NSArray *elements = [pair componentsSeparatedByString:@"="];
        NSString *key = [[elements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        NSString *val = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        
        [dict setObject:val forKey:key];
    }
    return dict;
}


- (void)applicationDidBecomeActive:(UIApplication *)application {

    if (self.launchedURL) {
        [self openLink:self.launchedURL];
        self.launchedURL = nil;
    }
    

}


- (BOOL)openLink:(NSURL *)urlLink
{
    
    NSLog(@"%@",urlLink);
    
    return YES ;

}







In Swift :-



Update your info.plist file
The very first step to add deep linking support for our app will  be to update our info.plist file. You can update the file by following the instructions in my video or open it as a source file and paste the following code snipped either at the top of the document(right after the opening <dict> tag) or at the bottom of your document(right before the </dict></plist> tags).


 <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>SwiftDeveloperBlogDeepLink</string>
            </array>
            <key>CFBundleURLName</key>
            <string>com.kargopolov.CodeExamples</string>
        </dict>

    </array>


Replace the value of CFBundleURLSchemes which is in my case “SwiftDeveloperBlogDeepLink” with a unique deep link url scheme that will make sense for your app. Just remember to make it short and unique.  And replace the value of CFBundleURLName with a value of Bundle Identifier of your app. You can check the video on how I do it.
Update AppDelegate.swift file
For your app to be able to listen to custom url schema clicks you will need to add the below function to your AppDelegate.swift file. This function is part of UIApplicationDelegate protocol.



func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
    
    print("url \(url)")
    print("url host :\(url.host!)")
    print("url path :\(url.path)")
    
    
    let urlPath : String = url.path as String!
    let urlHost : String = url.host as String!
    let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    
    if(urlHost != "swiftdeveloperblog.com")
    {
        print("Host is not correct")
        return false
    }
    
    if(urlPath == "/inner"){
        
        let innerPage: InnerPageViewController = mainStoryboard.instantiateViewController(withIdentifier: "InnerPageViewController") as! InnerPageViewController
        self.window?.rootViewController = innerPage
    } else if (urlPath == "/about"){
        
    }
    self.window?.makeKeyAndVisible()
    return true
}





To compile the code snippet about you will need to either create a new ViewController named “InnerPageViewController” and assign it an Identifier “InnerPageViewController” or edit this code to use a name of one of your existing view controllers.
And this is basically it. For the code about to work and open the inner page of my app when user clicks on a link in mobile browser, I need to create a link that will look like this:
  1. <a href="SwiftDevelop://swiftdeveloper/inner">Click here to switch to app</a>
where
  • “SwiftDevelop” –  is the custom URL Scheme name,
  • “swiftdeveloper” –  is the host name, which can be any other name you can come up with and use in the app’s business logic,
  • “inner” – is the custom schema url path which I used to compare and make decision which page to open for user.