Create an on-demand VPN connection programmatically in iOS 8

A while ago, I published a post about configuring and managing VPN connections programmatically in iOS 8. By default, established VPN connection will be disconnected if user iOS device goes to sleep to save battery life. To avoid this, Apple introduced a feature called on-demand; so, iOS will get connected to VPN whenever it needs to connect to the internet.

Well, it can be implemented programmatically too using the NetworkExtension framework and that’s exactly what this post is all about. In this post, I am going to create an on-demand VPN connection using NetworkExtension; therefore, VPN connection will be established whenever an app opens a network connection.

Note: I am not going to describe how to create a VPN connection in this post. If you’re not familiar with creating a VPN connection programmatically, please take a checkout my post.

Turn on On-Demand

The first thing you need to do is to tell the NetworkExtension framework that you want to create an on-demand connection. To do so, set the onDemandEnabled property to YES:

[[NEVPNManager sharedManager] setOnDemandEnabled:YES];

turning on-demand on is not enough. You will also need to tell the OS when exactly you want on-demand to be enabled. To do so, you will need to assign some rules to your configuration. These rules called “On-demand rules”:

What are On-demand rules?

On-demand rules are set of attributes which must be set to tell the OS when VPN connection should be established on-demand. onDemandRules property accepts an array of rules. Consequently, you can set multiple rules for a VPN configuration.

For example, you can set a rule and tell the OS to establish the VPN connection whenever user wants to open Apple.com; otherwise, the VPN connection won’t be established.

One thing you may want to do it to activate the VPN connection whenever an app open a network connection; so, all iOS network traffic will be transferred through your VPN server. To achieve this, NEOnDemandRuleConnect class must be used.

In Network Extension framework, Apple has provided some useful on-demand rule templates you can make use of. Although you can create your own rule, it’s possible to use templates as well.  NEOnDemandRuleConnect class is one of those templates. It will tell the OS to establish VPN connection whenever iOS needs to connect to the internet; as a result, users will always connect to your VPN servers whenever they want to access the internet. As far as I know, this is what most VPN providers and users want:

[[NEVPNManager sharedManager] setOnDemandEnabled:YES];
NSMutableArray *rules = [[NSMutableArray alloc] init];
NEOnDemandRuleConnect *connectRule = [NEOnDemandRuleConnect new];
[rules addObject:connectRule];
[[NEVPNManager sharedManager] setOnDemandRules:array];

Once you changed the configuration you have to save it using saveToPreferencesWithCompletionHandler: method.

Hope it helps 🙂

How to get persistent reference to a keychain item in iOS

Keychain is a very good idea from Apple. It lets app developers to store and retrieve sensitive data securely.

Keychain Services provides secure storage of passwords, keys, certificates, and notes for one or more users. A user can unlock a keychain with a single password, and any Keychain Services–aware application can then use that keychain to store and retrieve passwords. Keychain Services Programming Guide contains an overview of Keychain Services, discusses the functions and data structures that are most commonly used by developers, and provides examples of how to use Keychain Services in your own applications.

The following shows how keychain works:

unlocking_keychain. Photo taken from: developer.apple.com

During the process of creating VPN profiles programmatically in iOS 8, the NEVPNProtocol.passwordReference property requires a persistence reference to a keychain item with the kSecClassGenericPassword class. This post covers saving and getting persistence references to a keychain item in iOS.

Getting started with Keychain

The process of saving data in keychain is very simple once you understand it. To start working with Keychain, Security.framework needs to added to your project. Security framework has 4 major methods which enables you to access iOS keychain. These methods are:

  • SecItemAdd
  • SecItemCopyMatching
  • SecItemDelete
  • SecItemUpdate

As it can be guessed from each method’s name SecItemAdd, SecItemDelete and SecItemUpdate adds, deletes and updates data. SecItemCopyMatching method searches for a specific keychain item and copies item data to a reference variable if available. For more information about these four methods checkout Apple’s Keychain Services Reference page.

Saving data

Note: There’s actually no difference in saving normal and persistent references to the keychain!
The following adds a NSData object to the iOS keychain:

NSData *data = [Your data]; // Data to save. It can be a string too.
NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
[dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
NSData *encodedKey = [@"[Your key name]" dataUsingEncoding:NSUTF8StringEncoding];
[dict setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
[dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
[dict setObject:service forKey:(__bridge id)kSecAttrService];
[dict setObject:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
[dict setObject:data forKey:(__bridge id)kSecValueData];

OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dict, NULL);
if(errSecSuccess != status) {
    NSLog(@"Unable add item with key =%@ error:%ld",key,status);
}

After the data is saved it can be get anytime from keychain.

Getting Data

Data can be get from keychain using the following code:

NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
[dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
NSData *encodedKey = [@"[Your key name]" dataUsingEncoding:NSUTF8StringEncoding];
[dict setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
[dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
[dict setObject:service forKey:(__bridge id)kSecAttrService];
[dict setObject:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
[dict setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
[dict setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnPersistentRef]; // The most important part
    
CFTypeRef result = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)dict,&result);
    
if( status != errSecSuccess) {
    NSLog(@"Unable to fetch item for key %@ with error:%ld",key,status);
    return nil;
}
    
NSData *resultData = (__bridge NSData *)result; //Your data is ready

The most important part of the above code is in line 9 where kSecReturnPersistentRef attribute is set. This attribute tells the keychain to return a persistent reference to the keychain item.

Hope it helps 🙂

Quick post: Testing in-app purchases in iOS 8

I love quick posts, they’re short and handy. Some topics should be explained as short as possible. I name these quick posts. In this (quick) post, I want to talk about significant changes to iOS 8 simulator when testing in-app purchases; so, here you go:

iOS simulator - Photo taken from http://www.ralfebert.de/ios/ueberblick-ios-xcode/icon_simulator.pngTesting in-app purchases is one of the most important tasks to do in your applications; because, it’s the way you can make money from your app. In-app purchases were one of those features which had to be tested on a real device only.

Prior to iOS 8, developers had to have at least one real device (an iPod Touch for example) to test their apps’ in-app purchases. But in iOS 8, Apple has made significant changes to its iOS simulator. Now developers can do much more as it’s possible to test in-app purchase functionality right in the simulator even if no real device is available!

This is a very important improvement especially for me as a developer who is working with iOS 8 new feautres. If this feature was not available, I had to install iOS 8 beta on my iPhone which I prefer not to.

There might be more improvements in iOS simulator which I haven’t faced yet. If you know any of them, let the world know them as well by commenting down below.

Have a nice coding 😉

 

Configure and manage VPN connections programmatically in iOS 8

Update 3: If you’re going to create an on-demand VPN connection, checkout my article about creating on-demand VPN connection programmatically in iOS 8 after reading this.

Update 2: The beta 5 issue has been fixed in the GM release. Everything is currently working just fine.

Update: This solution does not work on iOS 8 beta 5 due to a weird “Missing name” issue; however, it works find on iOS 8 beta 1 to 4. If you know anything new about managing the VPN connections in iOS 8, let me know by commenting down below.

Connecting to VPN servers programmatically had been always an impossible task to do for developers because of Apple’s limitations.

In my previous post I’ve described that Apple introduced a brand-new Network Extension framework which gives developers the opportunity to configure VPN preferences programmatically but I didn’t describe how!

This post is a guide to manage VPN configurations in iOS 8 and OS X (10.10) Yosemite while there’s no official documentation published yet. I Also have to thank quellish who helped me a lot in this.

Requirements

  1. The very first and the most critical things you need is an actual device with iOS 8 beta 1 or above to test the app on! This tutorial cannot be tested on iPhone simulator. If you’re going to write a Mac application, OS X Yosemite Preview 3 or above has to be installed.
  2. Since this test doesn’t work on simulator, you have to be a member of iOS/Mac developer program. Also, you need to make some changes to your provisioning profile. You cannot use your iOS 7 provisioning profiles to develop iOS 8 VPN applications.
  3. Xcode 6 beta. By the time of this post (August 2nd, 2014), Xcode 6 is in beta 4 and just like I’ve mentioned in my previous post, you need to to a member of iOS/Mac program to have access to beta tools.
  4. Last but absolutely not least, you need a Mac since Xcode cannot be run on Windows or Linux machines.

Getting Started

The first thing you need to do before actually start writing any codes is to update your provisioning profiles. If you haven’t created any profiles yet, you need to create one now! To do this, login to your developer account, then click on “Certificate, Identifiers & Profiles”:

Provisioning profile update

Select Identifiers, then select the application you want to update its provisioning profile. If you don’t have any, you can create one using the plus sign. By selecting an app, a list will be appeared. This is a list of features the app is going to use, for example if you want to have iCloud functionality in your application, you have to turn iCloud feature on; otherwise, you won’t be able to test and deploy your iCloud based apps. The following is showing that list:

Identifiers list

By the introduction of iOS 8, a new item has been added to this list which is “VPN Configuration & Control”. This is exactly what we’re looking for! So enable this feature by clicking on it and then ticking its checkbox. When you turn this feature on a modal window will be displayed which describes its functionality:

Enable VPN Config

Enable VPN Configuration & Control feature and click “Done”. Then, download the provisioning profile again and replace it with the old one. We’re done here, now lets get back to Xcode.

Note: In this post I assume that you’re familiar with iOS development and Objective-C. If you’ve never developed any app in for iOS or Mac, you may need to learn some basic concepts and then return to this post.

Open Xcode and create a new iOS 8 single view application project. Then, place a button in the middle of screen and then connect it to your ViewController.

What we’re going to do is to setup VPN preferences on viewDidLoad: method and then connect to our specified VPN server when the button is tapped.

Before getting started, you have to know how all this work! If you understand the structure of Network Extension framework, then it will be much easier to develop apps based on it.

NetworkExtension.framework

Apple has done a brilliant job developing this framework. Every app can access system preferences but in its own sandbox; which means you cannot access other apps’ sandboxes.

First of all, saved preferences have to be loaded from OS to be able to be accessed. Once they’re loaded, it’s possible to make your changes. After changes have been made, they need to be saved. Unsaved preferences won’t be applied. Your app’s preferences can also be removed if you no longer need them. As a result, to create a VPN configuration we need to do the following:

  • Load our app’s preferences
  • Make our changes
  • Save preferences

Note that you need to load your app’s preferences even if you haven’t set any configuration yet.

After VPN connection is created we can connect to or disconnect from it.

Network extension contains three major classes:

  • NEVPNManager
  • NEVPNProtocol
  • NEVPNConnection

NEVPNManager is the most important class in this framework. It’s responsible for load, save and remove preferences. In fact, all VPN tasks have to be done through this class.

Create a new VPN connection

To get started a new instance of this class has to be created:

NEVPNManager *manager = [NEVPNManager sharedManager];

After NEVPNManager is initialized, system preferences can be loaded using loadFromPreferencesWithCompletionHandler: method:

[manager loadFromPreferencesWithCompletionHandler:^(NSError *error) {
    // Put your codes here...
}];

As I’ve mentioned in above code, the load method accepts a compilation handler block. This block is fired whenever the load process is completed. This block also has a parameter which is an NSError. the NSError parameter will be nil if the loading operation completed; otherwise, it will be non-nil. Accordingly:

[manager loadFromPreferencesWithCompletionHandler:^(NSError *error) {
    if(error) {
        NSLog(@"Load error: %@", error);
    } else {
        // No errors! The rest of your codes goes here...
    }
}];

After loading process is completed, It’s time to set up our VPN connection.

iOS 8 supports two major protocols. IPSec and IKEv2. It’s the first time that Apple offers IKEv2 protocol in its operating systems. This protocol is supported by all major operating systems including Android, Windows Phone, Windows Desktop, Linux and now iOS and Mac. In this post I’m going to talk about IPSec and in my next posts I’ll talk about IKEv2 as well. In addition to these protocols, Apple gives you the ability to create your own protocol if needed! This feature is a very important features for those who have implemented their own protocol; because now it’s possible to implement that protocol on iOS and Mac as well. OK, lets set up our IPSec protocol:

NEVPNProtocolIPSec *p = [[NEVPNProtocolIPSec alloc] init];
p.username = @"[Your username]";
p.passwordReference = [VPN user password from keychain];
p.serverAddress = @"[Your server address]";
p.authenticationMethod = NEVPNIKEAuthenticationMethodSharedSecret;
p.sharedSecretReference = [VPN server shared secret from keychain];
p.localIdentifier = @"[VPN local identifier]";
p.remoteIdentifier = @"[VPN remote identifier]";
p.useExtendedAuthentication = YES;
p.disconnectOnSleep = NO;

In the first line, I’ve created a new instance of NEVPNProtocolIPSec. This class is inherited from NEVPNProtocol class. NEVPNProtocol class is an abstract class you can use to create your own protocols.

Then, we specified our username and password in the second and third line. Notice that the password is a reference from Keychain; so, you need to store your password in Keychain first and then retrieve it.

The fourth line is our server address. Server address can be an IP, a host name or a URL.

Next is authentication method. iOS 8 supports three authentication methods

  • NEVPNIKEAuthenticationMethodNone: Do not authenticate with IPSec server.
  • NEVPNIKEAuthenticationMethodCertificate: Use a certificate and private key as the authentication credential.
  • NEVPNIKEAuthenticationMethodSharedSecret: Use a shared secret as the authentication credential.

As you can see, I’ve used Shared Secret method; but, you can use whatever method you want.

The next line is Shared Secret reference. Again it’s reference from Keychain; so, you need to get Shared secret from there. If you’re going to use certificate rather than shared secret. There’s no need to fill sharedSecretReference property; instead, you have to fill identityData property. Identity data is the PKCS12 data for the VPN authentication identity. The value for this property must be a NSData in PKCS12 format:

p.identityData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"clientCert" ofType:@"p12"]];

The next two lines are local and remote identifiers. These two are strings identifying the local and remote IPSec endpoints for authentication purposes.

The next property we need to set is useExtendedAuthetication. This is a flag indicating if extended authentication will be negotiated. This authentication is in addition to the IKE authentication used to authenticate the endpoints of the IKE session. For IKE version 1, when this flag is set X-Auth authentication will be negotiated as part of the IKE session, using the username and password properties as the credential. For IKE version 2, when this flag is set EAP authentication will be negotiated as part of the IKE session, using the username, password, and/or identity properties as the credential depending on which EAP method the server requires.

The last property to set is disconnectOnSleep. This boolean indicates whether the VPN connection must be disconnected when the device goes to sleep or not.

OK that’s enough for protocol. The next thing we have to do is to assign the protocol we’ve just created to the VPN manager. To do so, the setProtocol: method can be used.

[manager setProtocol:p];

IPSec and IKEv2 protocols have a very cool feature called On-demand. This feature enable connect to connect automatically whenever user attempted to connect to the internet. In iOS 8, it’s possible to enable on-demand on the connection. But, I’m going to cover this feature in another post; therefore, lets leave it for now and set the onDemandEnabled property to NO for now.

[manager setOnDemandEnabled:p];

The last thing we must set is the description of VPN preference we’re going to create. To do so, just set its localized description property by using setLocalizedDescription: method

[manager setLocalizedDescription:@"[You VPN configuration name]"];

We’re almost done. We’ve set up the configuration but haven’t saved it yet. To save the configuration simply call the saveToPreferencesWithCompletionHandler: method:

[manager saveToPreferencesWithCompletionHandler:^(NSError *error) {
    if(error) {
        NSLog(@"Save error: %@", error);
    }
    else {
        NSLog(@"Saved!");
    }
}];

This method simply saves your specified configuration to the system settings.

Connect to the VPN connection we’ve just created

Now that you’ve saved your settings to system’s preferences, it’s time to connect to it. NEVPNManager has a property called connection. This property is an object of NEVPNConnection class. It hold information which is responsible for VPN connection. To connect to VPN server you’ve just created, simply call startVPNTunnelAndReturnError: method of NEVPNConnection class just like below:
Run the application on your device and you’ll see and new connection will be create and you can connect to it by tapping the button. Also, you can disconnect from VPN server programmatically as well by calling stopVPNTunnel method of NEVPNConnection:

- (IBAction)buttonPressed:(id)sender {
    NSError *startError;
    [[NEVPNManager sharedManager].connection startVPNTunnelAndReturnError:&startError];
    
    if(startError) {
        NSLog(@"Start error: %@", startError.localizedDescription);
    } else {
        NSLog(@"Connection established!");
    }
    
}

If you have any idea, suggestion or anything else regarding this post, please leave your comments down below. I’ll blog about IKEv2 and On-demand features in the near future. Stay tuned.

Storyboards are now available on OS X Cocoa development

One of the coolest things I love to work with when develop iOS applications is using storyboards. They’re definitely one of the best ways to develop application in my opinion because, they’re very simple and simplify a lot of development tasks, cover most application scenarios and easy to understand as most iOS developers tend to use them.

In recent Apple WWDC (2014), a new version of Xcode (6) has been introduced. This version has a lot of cool features not only for iOS 8 but OS X as well! One of the most surprising features in this version is the support of storyboards for OS X Cocoa development! Using Xcode 6, Mac developers can take advantage of storyboards! Let’s take a look:

Download Xcode 6 from Apple’s developer website. (By the time, Xcode 6 is in beta; consequently, you must be a member of Mac/iOS developer program to be able to download it)

Create a new OS X Cocoa Application. The following window will be appeared:

osx-app-create

As you can see in the above screenshot, you now have the ability to create an OS X Cocoa application and use storyboards.

But, you may ask this question: Why this option is disabled here?

Well, the answer is clear! This feature is only available in the latest version of OS X which is by the time OS X 10.10 Yosemite; as a result, you must install it to use storyboards in your applications.

I believe this improvement to Cocoa development, will courage more developers to release the Mac version of their apps. Most iOS developers today have not worked with older technologies such as nib files because when they started iOS development, storyboards were existed and they didn’t need anything else. But now they can do the same thing in Mac applications as they do in iOS.

Hope it helps

Introducing Network Extension in iOS 8 and OS X 10.10

It’s about a year I’m working on an iOS VPN project which enables users to access the web and its contents without any kind of restrictions. By the time, all VPN applications need to install a configuration profile on clients’ devices to apply their VPN configuration on them; because, Apple forbids applications to access iOS system configurations. After the installation of configuration profile, users have to open iOS settings application to enable that VPN service manually; consequently, client applications are act as a profile installer or statistics viewer only!iOS-8-App-Extensions-icon-200x200

The story is completely different on Android devices since restrictions are much fewer than iOS. Android developers can implement a connect/disconnect button to let their users connect and disconnect from VPN servers right from the app.

By introduction of iOS 8, Apple revealed lots of new developer tools and APIs including App Extensions, Handoff, HealthKit, HomeKit, Swift programming language and many many more. But, one of the most useful stuff specially for VPN providers is NetworkExtension which is first introduced in iOS 8 and OS X 10.10!

Network Extension enables developers to manage VPN preferences on their users’ devices. By using this framework, you will have access to almost all iOS VPN preferences. In addition to letting developers access VPN settings, Apple also introduced a new IKEv2 protocol which wasn’t available on iOS or OS X before. This is a standard protocol which is supported by all major mobile and desktop operating systems such as Windows Phone 8.1, Android and now iOS!

I plan to publish more posts about new stuff in both iOS 8 and OS X 10.10. Unfortunately, by now, Apple hasn’t released any documentations regarding Network Extension; but, I’ve done some researches and I’ll share them with you in near future. Until then, please share your idea and information about network extension with me so I can provide a better post to publish 🙂

 

How to create installation DMG files in OS X

One of the coolest features of Mac OS in comparison with Windows is the simplicity of apps’ installation. In Windows, in most cases, there should be an installation package; otherwise, the app won’t run correctly. On the contrary, Mac apps installations are much simpler. All you need to do is to copy the app bundle to the Applications folder; so, no installation is needed. The installation process of Skype for Mac is a very good example. To install Skype you just need to drag the app icon into the Applications folder. by doing this, you’re copying the Skype app bundle to your Applications folder. The following is the Skype installation page for OS X:

skype_installation_dms

Now how can you create such installation page for your own app?

First of all, look at the picture above. The installation page contains three major sections:

  • The First is the application bundle (in this case, Skype.app).
  • The second is the OS X Applications folder.
  • The third one is the background image of the installation page.

These three things are the requirements to create a DMG installation file. However, you can ignore the background image and let it be just a solid white color background, it’s much better to have a custom background color or image for your installation page. It make your installer more friendly and of course more beautiful. In addition, there is one more requirement (which is obvious of course): You will need a Mac machine to build DMG installation files. As far as I know, you cannot create DMG installation files in Windows.

Getting Started

After all of three requirements I’ve mentioned above were present, you can get started. I decide to break this tutorial into steps so it’s much easier to understand:

The very first thing to do is to create an empty DMG file so we can put our custom files in it. To do so, OS X has a built-in tool named Disk Utility. You can simply search for it in spotlight search box (On the top right of your screen).

disk_utility_home

In the Disk Utility home page click New Image button on the top of screen. When New Image button is clicked, a window will be appeared like the following:

disk_utility_new_image

There are some settings in the New Image window which need your consideration. The first field is the path of your DMG file that is going to be created. The second field is name. It is recommended to set this field as the name of your application because users will see this name when they mount your DMG file on their machine. The third field is size of disk image. Unfortunately, disk images’ file sizes could not be dynamically allocated so you need to pick a size which is right for your application’s size. It’s recommended to choose a size which is a little larger than your application bundle (The minimum size of disk image is 21MB in OS X). The forth field is image format. This field’s value is set to Mac OS extended by default and there’s no need to change it; so, leave it as it is. Encryption and Partitions fields are fifth and sixth fields in the New Image window which should be left as the default value. We don’t need any encryption or partitioning for now. The last field, Image Format, is sightly important here. You have to set this field’s value to read/write disk image. You won’t be able to create the installation DMG if you select anything else! After setting all fields, click “Create” to create the disk image.

By clicking “Create” your disk image will be created and will be automatically mounted. Close Disk Utility, go to Desktop and double-click on the mounted image to see its content. You can see the disk image is empty as you expected. In the next section we need to fill it by adding our custom files. The reason we’re able to add files to our disk image is because we set the image format field to “read/write disk image”.

It’s time to add our custom-designed background image to our installation (If you don’t want to add an image to your installation page, you can skip this section).
You can simply drag your custom background image to the mounted disk. As you can see the file has been copied to the disk image but has not set as disk image background. To do so, right click on the mounted image on your mac desktop and select Show View Options.

myapp_show_view_optionsThere are two things that need to be taken care of in the Show View Options page. The first one is Icon Size and the second is Background.

Icon Size indicates the size of our two main icons in the installer page (Our two icons are your app bundle icon and the Applications icon). Icon size is completely up to you. In the Skype example I’ve mentioned earlier, the icon size is set to the maximum which is 128*128 pixels. I myself prefer to use the maximum as well; because, it makes it easier for users to do the drag-drop action.

After setting the icon size, it’s now time to set the background image. Just select picture item from background radio button group and then DRAG the image you’ve just copied into the disk image (not from other paths of your hard drive) to the “Drag image here” section. As soon as you drop the image, the background will be set. There’s no Save button. All changes will be saved automatically; so, you can close Show View Options window. You can also resize the disk image window by its corners (as same as what you do when want to resize other windows in OS X) to fit your window size with the background image.

The interesting part is that all of your actions will be kept and the next time you open your disk image, background image, icon size and window size is saved.

Note: DO NOT CLICK ON “USE AS DEFAULT” BUTTON. IT WILL SET YOUR SPECIFIED CONFIGURATION INCLUDING BACKGROUND IMAGE TO ALL FOLDERS ON YOUR MAC.

As you may have noticed, The image file is in the middle of disk image window. We need to make it hidden so users can’t see it. There are plenty of ways to make a file hidden but one of the coolest ways is to add a “.” to the first of file name. In Unix systems like Mac, files which are started by a “.” are hidden by default. You can’t change the file name in the finder. You need to rename the file in terminal. So open a terminal window and do the following:

cd /Volumes/[YOUR DISK IMAGE NAME]
mv [YOUR BACKGROUND FILE NAME] .[YOUR BACKGROUND FILE NAME]

As you can see the file is now hidden!
The next step is to copy our app bundle. To do it just copy the app bundle to your disk image. You can also change the location of app bundle to any place of disk image we want. After the bundle has been copied, We need to make an Application icon so use can drag the app to it. To do so, go to you Macintosh HD, click on Applications, hold Command and Option key, and drag it to the disk image window. By holding Command+Option it will make an alias of that folder. Note that we’re not copying the Applications folder, we’re just making an alias from it. Place the two icons near each other so it’s easier for users to install the app.

We’re almost done. Your installation DMG file is ready; but, there is something. By publishing this DMG file, all users can change its background image, icon size, window size, and etc. In fact, they can do whatever you can! To prevent this, we need to make this disk image read-only.
Eject the disk image by right-clicking on disk image icon and selecting “Eject”. Re-open the Disk Utility tool again. On the left side of Disk Utility home pas select the DMG file we’ve created, then, select Convert. The convert window will show up. select a unique name for it and from Image Format select read-only. Click save to create a new disk image from your selected one. The new DMG file we’ve just created is read-only can be safely published and others cannot make changes to it.

If you have any question, don’t hesitate a moment; just ask it on the comments down below 🙂
Hope it helps.

If you’re using Flurry, update it before submitting your app to the AppStore

Previously, I blogged about how awesome is Flurry, a free analytics system you can use in your mobile apps. I also blogged about why Apple rejected my app and made me resubmit my app. In that post, I’ve described the reason Apple rejected my app was because of using AdSupport.framework.

After cleaning my app from AdSupport.framework and resubmitting it to the AppStore, I got rejected again! So I started to argue with apple and also searched a lot on the internet until I found this StackOverflow question. People were arguing that Apple also rejected their apps too because of using AdSupport.framework whereas they haven’t used it in their applications!

As a result, I decided to contact Flurry support to see if there’s any problem with their SDK. When I logged in to my Flurry account, I saw this:

FlurryMessage

It seems Flurry was also using AdSupport.framework for device identification and since Apple forbids it, they updated their SDK as well 🙂

Therefore, if you’re using third-party SDKs such as Flurry you need to update to the latest version before submitting your app to the AppStore. As far as I know, By the time, other third-party libraries like Google Analytics, Facebook SDK and TestFlight are also having this issue and you should get their latest SDK to prevent your app from being rejected.

The difference between advertisingIdentifier and identifierForVendor in iOS

Last week I resubmitted my first iOS app to the AppStore due to its rejection for using AdSupport.framework while there was no ad functionality in it. Since using AdSupport.framework is forbidden in my app which doesn’t have ad functionality, I used the identifierForVendor property from UIDevice to get device’s unique identifier instead of advertisingIdentifier as Apple described here.

Unfortunately, identifierForVender property does not return the device unique identifier. In fact, this identifier changes if the app change!

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. Normally, the vendor is determined by data provided by the App Store. If the app was not installed from the app store (such as when the app is still in development), the vendor is determined based on the app’s bundle ID. The bundle ID is assumed to be in reverse-DNS format, and the first two components are used to generate a vendor ID. For example,com.example.app1 and com.example.app2 would appear to have the same vendor ID.

The value of identifierForVender property will return a same static identifier value but if a user reinstall the application, value of this property will change! WHAT A FAIL! This is not so good at all! As a result, the value of this property is not device-dependent anymore and it’s impossible to track users’ devices.

advertisingIdentifier property will always return a value no matter what application you’re developing on but identifierForVender changes every time user install an app!

Hope it helps.

My first ever iOS app has rejected by Apple. But Why?

Near a week ago I submitted my first ever iOS app to the App Store. As you may know, it takes about 5 business days for Apple to review your app and it will be approved if everything is OK!

But, things are not as good as  you expect all the time. Yes, my very first app has rejected! But why? The apple told me that I’ve included a library in my application but haven’t used it.

We found your app uses the iOS Advertising Identifier but does not include ad functionality. This does not comply with the terms of the iOS Developer Program License Agreement, as required by the App Store Review Guidelines.

According to the above issue I started to search my application to see if I have used this library. Actually, the best way to do so is to remove the library reference and rebuild the app. If you haven’t been used the specified library in your application’s code it will be built successfully. But in my case, I HAVE been used the library! In fact when I removed the AdSupport.framework reference from my application, the build process failed!

The reason I have used this library in the app was to get device identifier for security purposes. Below is the code I was used to get device identifier:

NSString *deviceIdentifier = [ASIdentifierManager.advertisingIdentifier UUIDString]

As I searched the web to find a solution for this issue I found an article which was released on August 22, 2013 by Apple:

If your apps use the MAC address to identify an iOS device, the system will return the same static value for all devices running iOS 7. Please update your apps to use the identifierForVendor property of UIDevice. If you need an identifier for advertising purposes, use the advertisingIdentifier property of ASIdentifierManager.

So I changed my code to this:

NSString *deviceIdentifier = [[UIDevice currentDevice].identifierForVendor UUIDString]

Both methods will return device’s identifier but the last method doesn’t require AdSupport.framework.

Anyway, I resubmitted my app to the App Store and should wait for another 5 business days to see if Apple approves it.