Monthly Archives: June 2014

Eclipse: Running Maven As External Tool

I am an iOS developer by profession. Recently, I created my first mac app and a website to promote it. During website development, I used Maven for managing dependencies by integrating it with Eclipse as an External Tool. Later on, I learnt about an Eclipse plug-in called m2e which makes using Maven with Eclipse a breeze. m2e uses its own distribution of Maven packaged with the plugin. But I am yet to give m2e a try.

So for those of you like me who have a standalone Maven installation and want to use it with Eclipse without installing the m2e plugin, you can do it as follows

  1. Go to Eclipse > Run Menu > External Tools > External Tools Configuration.
  2. In the left pane, select Program and click on add new configuration.
  3. Add a name for the configuration in the Name field. I have used Clean ExpenseTrack.
  4. Provide the path where the Maven executable (mvn) file is located for Location field. On my Mac, I had it at /Users/Sayeed/apache-maven-3.1.1/bin/mvn. Windows users should give <path-to-maven-installation>/bin/mvn.bat
  5. Provide the path where your project file is located for Working Directory field.
  6. Provide the mvn command for Arguments field. In this example, I have used clean.

external_tools

That’s it. You are ready to use mvn clean command by clicking Run. The command’s output gets redirected to Eclipse Console. You can add more commands following the same steps. Cheers!!!.

Advertisements

Mac App Store Build Validations

I recently submitted my first Mac App to the Mac App Store. Before submission, I ran a bunch of validation steps on my final production ready app. Craig Hockenberry’s blog post made it much easier. Here are the key steps

  1. Launch Terminal app and cd to the dir where the .app file is located.
  2. Recursively finds all Mach-O bundles in the app bundle.
    $ find -H Myapp.app -print0 | xargs -0 file | grep "Mach-O"
    
    Myapp.app/Contents/Frameworks/CorePlot.framework/CorePlot:                                                  Mach-O 64-bit dynamically linked shared library x86_64
    
    Myapp.app/Contents/Frameworks/CorePlot.framework/Versions/A/CorePlot:                                       Mach-O 64-bit dynamically linked shared library x86_64
    Myapp.app/Contents/Frameworks/CrashReporter.framework/CrashReporter:                                        Mach-O universal binary with 2 architectures
    Myapp.app/Contents/Frameworks/CrashReporter.framework/CrashReporter (for architecture x86_64):	            Mach-O 64-bit dynamically linked shared library x86_64
    Myapp.app/Contents/Frameworks/CrashReporter.framework/CrashReporter (for architecture i386):		    Mach-O dynamically linked shared library i386
    Myapp.app/Contents/Frameworks/CrashReporter.framework/Versions/A/CrashReporter:                             Mach-O universal binary with 2 architectures
    Myapp.app/Contents/Frameworks/CrashReporter.framework/Versions/A/CrashReporter (for architecture x86_64):   Mach-O 64-bit dynamically linked shared library x86_64
    Myapp.app/Contents/Frameworks/CrashReporter.framework/Versions/A/CrashReporter (for architecture i386):     Mach-O dynamically linked shared library i386
    Myapp.app/Contents/Frameworks/Growl.framework/Growl:                                                        Mach-O universal binary with 2 architectures
    Myapp.app/Contents/Frameworks/Growl.framework/Growl (for architecture x86_64):	                            Mach-O 64-bit dynamically linked shared library x86_64
    Myapp.app/Contents/Frameworks/Growl.framework/Growl (for architecture i386):	                            Mach-O dynamically linked shared library i386
    Myapp.app/Contents/Frameworks/Growl.framework/Versions/A/Growl:                                             Mach-O universal binary with 2 architectures
    Myapp.app/Contents/Frameworks/Growl.framework/Versions/A/Growl (for architecture x86_64):	            Mach-O 64-bit dynamically linked shared library x86_64
    Myapp.app/Contents/Frameworks/Growl.framework/Versions/A/Growl (for architecture i386):	                    Mach-O dynamically linked shared library i386
    Myapp.app/Contents/MacOS/Myapp:                                                                             Mach-O 64-bit executable x86_64

    I have colored the important ones in green. They are the bundles of interest. The others are just aliases. Certain universal (32 bit and 64 bit) bundles are shown twice but you will see only one bundle in the location pointed to. My application had only frameworks and the main executable but in your case there could be other bundles as well.

  3. Verify the Entitlements of all the bundles of interest.
    //This bundle has Entitlements
    $ codesign -d --entitlements - /Users/Sayeed/Desktop/Myapp.app/
    
    Executable=/Users/Sayeed/Desktop/Myapp.app/Contents/MacOS/Myapp
    ??qq?<?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    	<key>com.apple.application-identifier</key>
    	<string>83YFQ426C5.com.app.*>/string>
    	<key>com.apple.security.app-sandbox</key>
    	<true/>
    	<key>com.apple.security.files.user-selected.read-write</key>
    	<true/>
    	<key>com.apple.security.network.client</key>
    	<true/>
    	<key>com.apple.security.print</key>
    	<true/>
    </dict>
    </plist>
    
    //This bundle doesn't have entitlements
    $ codesign -d --entitlements - /Users/Sayeed/Desktop/Myapp.app/Contents/Frameworks/CrashReporter.framework/Versions/A/CrashReporter
    
    Executable=/Users/Sayeed/Desktop/Myapp.app/Contents/Frameworks/CrashReporter.framework/Versions/A/CrashReporter
    
  4. Verify the Code signatures and Designated Requirements (DR) of all the bundles of interest.
    $ codesign --verify --verbose=4 /Users/Sayeed/Desktop/Myapp.app
    
    /Users/Sayeed/Desktop/Myapp.app: valid on disk
    /Users/Sayeed/Desktop/Myapp.app: satisfies its Designated Requirement
    
    $ codesign --verify --verbose=4 /Users/Sayeed/Desktop/Myapp.app/Contents/Frameworks/CorePlot.framework/Versions/A/Coreplot
    
    /Users/Sayeed/Desktop/Myapp.app/Contents/Frameworks/CorePlot.framework/Versions/A/Coreplot: valid on disk
    /Users/Sayeed/Desktop/Myapp.app/Contents/Frameworks/CorePlot.framework/Versions/A/Coreplot: satisfies its Designated Requirement
    Important: Xcode on Mac OS X Maverics doesn’t allow you to sign a bundle if any nested bundle in it is unsigned. These nested bundles could be things like helper executables, libraries, embedded frameworks, plug-ins, XPC services. Therefore

    1. You should sign the unsigned bundles with your own code signing identity i.e. your Developer Id Certificate or App Store Distribution Certificate.
    2. It is recommended that you re-sign the bundles that are already signed by third parties with your own code signing identity i.e. your Developer Id Certificate or App Store Distribution Certificate.

    Here is how you should do it.

  5. Verify the Identifiers, Signer Details and Trust Chain, Designated Requirements (DR) of all the bundles of interest.
    $ codesign --display --requirements - --verbose=4 Myapp.app/
    
    Executable=/Users/Sayeed/Desktop/Myapp.app/Contents/MacOS/Myapp
    Identifier=com.app.myapp
    Format=bundle with Mach-O thin (x86_64)
    CodeDirectory v=20200 size=3804 flags=0x0(none) hashes=181+5 location=embedded
    Hash type=sha1 size=20
    CDHash=4145a92202f852303290579c641dab3c36336b1f
    Signature size=4353
    Authority=3rd Party Mac Developer Application: Sayeed Hussain (83YFQ426C5)
    Authority=Apple Worldwide Developer Relations Certification Authority
    Authority=Apple Root CA
    Signed Time=13-Jun-2014 12:10:11 am
    Info.plist entries=35
    TeamIdentifier=83YFQ426C5
    Sealed Resources version=2 rules=12 files=49
    designated => identifier "com.app.myapp" and anchor apple generic and certificate leaf[subject.CN] = "3rd Party Mac Developer Application: Sayeed Hussain (83YFQ426C5)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */
    
    $ codesign --display --requirements - --verbose=4 Myapp.app/Contents/Frameworks/CrashReporter.framework/Versions/A/CrashReporter
    
    Executable=/Users/Sayeed/Desktop/Myapp.app/Contents/Frameworks/CrashReporter.framework/Versions/A/CrashReporter
    Identifier=coop.plausible.CrashReporter
    Format=bundle with Mach-O universal (i386 x86_64)
    CodeDirectory v=20200 size=1532 flags=0x0(none) hashes=69+3 location=embedded
    Hash type=sha1 size=20
    CDHash=3195a79f058becf75f663cd1fea96d9f75c7ba4b
    Signature size=4353
    Authority=3rd Party Mac Developer Application: Sayeed Hussain (83YFQ426C5)
    Authority=Apple Worldwide Developer Relations Certification Authority
    Authority=Apple Root CA
    Signed Time=13-Jun-2014 12:10:10 am
    Info.plist entries=16
    TeamIdentifier=83YFQ426C5
    Sealed Resources version=2 rules=12 files=22
    designated => identifier "coop.plausible.CrashReporter" and anchor apple generic and certificate leaf[subject.CN] = "3rd Party Mac Developer Application: Sayeed Hussain (83YFQ426C5)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */
  6. If you are building for Mac App Store skip this step. If you are distributing outside of the Mac App Store, this is the last step. Verify that Gatekeeper will accept your app.
    $ spctl --verbose=4 --assess --type execute /Users/Sayeed/Myapp.app
    
    /Users/Sayeed/Myapp.app: accepted
    source=Developer ID
    

    and you are done.

  7. If you are distributing via the Mac App Store, follow this and the next step. You need to first create an xcarchive by choosing Product > Archive in Xcode. Then, using Terminal, you need to export it as a .pkg file as shown.
    $ xcodebuild -exportArchive -exportFormat PKG -archivePath  /Users/Sayeed/Desktop/Myapp\ 13-06-14\ 12.10\ am.xcarchive -exportPath /Users/Sayeed/Desktop/Myapp -exportSigningIdentity "3rd Party Mac Developer Application: Sayeed Hussain (83YFQ426C5)" -exportInstallerIdentity "3rd Party Mac Developer Installer: Sayeed Hussain (83YFQ426C5)"
    productbuild: Adding component at /var/folders/g3/spw0ywfj4d3_rz8jbkxz4lt80000gn/T/28EB1C81-63CD-444C-96BE-9BF8DA01A34E-4171-000001432522843D/Myapp.app
    productbuild: Signing product with identity "3rd Party Mac Developer Installer: Sayeed Hussain (83YFQ426C5)" from keychain /Users/Sayeed/Library/Keychains/login.keychain
    productbuild: Adding certificate "Apple Worldwide Developer Relations Certification Authority"
    productbuild: Adding certificate "Apple Root CA"
    productbuild: Wrote product to /var/folders/g3/spw0ywfj4d3_rz8jbkxz4lt80000gn/T/28EB1C81-63CD-444C-96BE-9BF8DA01A34E-4171-000001432522843D/Myapp.pkg
    productbuild: Supported OS versions: [10.7, )
    Moving exported product to '/Users/Sayeed/Desktop/Myapp.pkg'
    ** EXPORT SUCCEEDED **
    
    

    Myapp.pkg file will get generated.

  8. Verify the Myapp.pkg file by running the installer with -store option.
    $ sudo installer -store -pkg /Users/Sayeed/Desktop/Myapp.pkg
    
    installer: Note: running installer as an admin user (instead of root) gives better Mac App Store fidelity
    installer: Myapp.pkg has valid signature for submission: 3rd Party Mac Developer Application: Sayeed Hussain (83YFQ426C5)
    installer: Installation Check: Passed
    installer: Volume Check: Passed
    installer: Bundle com.app.myapp will be installed to /Applications/Myapp.app
    installer: Starting install
    installer: Install 0.0% complete
    installer: Install 13.8% complete
    installer: Install 22.2% complete
    installer: Install 47.6% complete
    installer: Install 88.3% complete
    installer: Install 100.0% complete
    installer: Finished install
    

    and you are done.

Hope this comes handy to anyone submitting their app to the Mac App Store. That’s it for now. Good Luck And Good Life!!!

Mac App: Code Signing Frameworks

Until the introduction of Gatekeeper in Mac OS X 10.8, the concept of code signing (introduced in Mac OS X 10.5) was not so well discussed in the Mac developer community. Gatekeeper is a security feature introduced by Apple to ensure that Mac apps coming only from either App Store or from Registered Apple Developers (via their websites) are allowed to run on a User’s Mac by default. Users have the option of changing Gatekeeper settings at their own risk to allow apps from any source to run but most users don’t exercise that option.

Gatekeeper requires apps to be properly code signed. An app is considered properly code signed if the main executable and all the nested bundles (embedded frameworks, libraries, helper executables, plug-ins etc) contained in it are properly code signed.

Important: Xcode on Mac OS X Maverics doesn’t allow you to sign a bundle if any nested bundle in it is unsigned. These nested bundles could be things like helper executables, libraries, embedded frameworks, plug-ins, XPC services. Therefore

  1. You should sign the unsigned bundles with your own code signing identity i.e. your Developer Id Certificate or App Store Distribution Certificate.
  2. It is recommended that you re-sign the bundles that are already signed by third parties with your own code signing identity i.e. your Developer Id Certificate or App Store Distribution Certificate.

Code Signing Bundles The Wrong Way

Some googling would lead you to a “quick” fix on the internet to recursively sign all the nested bundles in your app. The “quick” fix is to use codesign’s –deep option in “Other Code Signing Flags” in your target’s build settings. But this solution is incorrect due to the fact that while recursively signing the nested bundles, –deep applies top-level bundle parameters like your app’s Entitlements to all the nested bundles rendering them invalid.

When users download and install such an app, Gatekeeper will notify them that it is damaged and cannot be opened. If you check the app using command line, here is what you get

$ spctl --verbose=4 --assess --type execute /Users/Sayeed/Myapp.app
/Users/Sayeed/Myapp.app: a sealed resource is missing or invalid

Code Signing Bundles The Right Way

The right way to code sign nested bundles is to add another Build Phase to your target.

When you embed frameworks, you add a “Copy Files” build phase to copy them into the Frameworks folder in your app bundle. This enables the app to run on the users’ systems because these frameworks don’t ship by default on Mac OS X. To code sign embedded frameworks after they are copied, add a Run Script Build Phase from Xcode > Editor > Add Build Phase. The Shell is bash (/bin/sh) and the script looks like

LOCATION="${BUILT_PRODUCTS_DIR}"/"${FRAMEWORKS_FOLDER_PATH}"
IDENTITY="3rd Party Mac Developer Application: Sayeed Hussain (83YFQ426C5)"
codesign --verbose --force --sign "$IDENTITY" "$LOCATION/Coreplot.framework/Versions/A"
codesign --verbose --force --sign "$IDENTITY" "$LOCATION/CrashReporter.framework/Versions/A"
#other embedded frameworks
Important: Frameworks are “versioned bundles”, and each contained version should be signed and validated separately. For example:
$ codesign -s my-signing-identity ../MyCustomFramework/Versions/A
$ codesign -s my-signing-identity ../MyCustomFramework/Versions/B
All embedded frameworks need to be signed separetly by adding the codesign command in the shell script.

If you are bulding to distribute outside of the Mac App Store, you should use your “Developer ID Application” code signing identity. If you are building for the Mac App Store, you should use your “3rd Party Mac Developer Application” code signing identity. Other embedded bundles like helper executables, plug-ins or XPC services, need to be signed appropriately after being copied into the app bundle.

Go ahead and code sign your embedded frameworks the right way. That’s it for now. Good Luck And Good Life!!!

I got an App Store Rejection

I am an iOS developer by profession. Recently, I decided to pursue an idea of my own and at the same time diversify my skill set. Ergo, I decided to build my first Mac App. So I quit my job and started working on my idea. After a few months of hard work on the Mac App and the website and a few hiccups, I was ready to submit the app to app store. Praying to god for good luck but also slightly dreading the worse, I pressed the Upload button. Three days later, lo and behold! I was staring at a REJECTI@N from Apple for these reasons:

    2.1: Apps that crash will be rejected
    2.21: Apps may not use update mechanisms outside of the App Store
    2.5: Apps that use non-public APIs will be rejected

Bad news I said to myself. But not only was I determined to push the app through, I already had the roadmap for the next version ready. There was no way I was going to let this setback slow me down even for a moment. I sat down and rectified the errors as follows:

2.1: Apps that crash will be rejected

There were two crashes noticed by Apple and they had attached the crash reports for debugging.

  1. Looking at the logs, Crash1 happened due to NSPortTimeoutException when NSSpellChecker class is used by the app for the first time after system start. I was using it to give users auto-suggestions as they start typing in a textfield. In my code, I was doing my own exception handling using the ExceptionHandling.framework. I changed my
    - (BOOL)exceptionHandler:(NSExceptionHandler *)sender shouldHandleException:(NSException *)exception mask:(NSUInteger)aMask{
            
    }
    

    method’s implemetation. That fixed it.

  2. Crash2 was related to MASRecieptValidation workflow. The app checked for the presence of a valid MacAppStore receipt stored in ExpenseTrack.app/Contents/_MASReceipt. When an app is downloaded from the Mac App Store, this receipt is installed by default and receipt validation succeeds. But while Apple was reviewing it, this receipt was absent and the app exited with exit code 173. During my testing, I created a test account on iTunesConnect to generate a dummy receipt. I said Apple that if they wanted to test the dummy receipt generation/validation workflow, they can followed these steps:
    1. Kill storeagent using killall -KILL storeagent (without this, the sign in prompt was not showing. Please refer to http://furbo.org/2013/10/21/mac-app-store-receipts-and-mavericks/ for more details).
    2. Delete, install and launch the app.
    3. The app runs its receipt validation code which fails because the receipt is absent (this won’t happen when the app is installed from Mac App Store because the receipt will be installed by default).
    4. The app quits with exit code 173 signalling storeagent to get a valid receipt.
    5. Storeagent prompts users to sign in with Apple Id and fetches and installs the receipt in the ExpenseTrack.app/Contents/_MASReceipt folder and then relaunches the app.
    6. The receipt validation code succeeds because the receipt is now present.

    That fixed it.

2.21: Apps may not use update mechanisms outside of the App Store

In the app, I had provided a Check For Updates menu option to allows users to check for updates. Apple thought that through this option I was providing an update mechanism outside of the App Store. I don’t blame them because on the face of it, it appeared so. But it wasn’t as it looked. Here is how it worked:

  1. I upload an new version to iTunesConnect and update my back-end(server) with that version number once it goes live.
  2. The app when launched makes an http request to our back-end to check for the latest available app store version.
  3. The app receives and compares it with its own version. If received version > app’s version, it generates a Growl/NSUserNotificationCenter notification which when clicked launches the App Store app on the Mac using macappstore://myappurl. This loads the app’s page in the App Store app allowing users to download the new version.

So you see, it wasn’t as it looked. But I removed the option without arguing my case any further with Apple.

2.5: Apps that use non-public APIs will be rejected

This is what Apple said, “The app includes OBJC_IVAR_$_NSView._frame from the framework ‘/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit'”. This was a little unexpected. I somehow ended up using NSView’s _frame iVar (private iVar) directly in a subclass of NSView in my code. I used otool and nm as suggested by Apple to identify the culprit class and changed the iVar usage.

After these changes I was ready to go again. I hit the Upload button once more after saying my prayers of course. Three days later, lo and behold! the app was Ready For Sale. June 16th 2014, 10:56 AM was a happy moment for me. My first Mac app had been released. All the perseverance had paid off. I thanked god, heaved a big sigh, pat myself on the back and started work on the next version. I wish everyone Good Luck And Good Life!!!

Order of #import and Xcode new api usage warnings

I recently wrote a blog post about redefining some macros present in system headers to generate new api usage warnings in Xcode. This is helpful when your Mac app’s deployment target is lower than your XCode SDK version. Here is how the code snippet looked

//  MyProject-Prefix.pch
//  Prefix header
//  The contents of this file are implicitly included at the beginning of every source file.

#ifdef __OBJC__
        
        #import <Foundation/NSObjCRuntime.h>
        
        #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_7
            #undef  AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
            #ifdef __clang__
                #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER __attribute__((weak_import, deprecated("API is newer than Deployment Target.")))
            #else
                #define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER WEAK_IMPORT_ATTRIBUTE
            #endif
        #endif
    
        #undef  NS_CLASS_AVAILABLE
        #define NS_CLASS_AVAILABLE(_mac, _ios) AVAILABLE_MAC_OS_X_VERSION_##_mac##_AND_LATER

        #undef  NS_ENUM_AVAILABLE
        #define NS_ENUM_AVAILABLE(_mac, _ios) AVAILABLE_MAC_OS_X_VERSION_##_mac##_AND_LATER

        #import <Cocoa/Cocoa.h>
        
#endif

Let’s dissect this code snippet a little. Let’s talk about why putting this

#import <Foundation/NSObjCRuntime.h>

then

#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_7
.
.
.
define NS_ENUM_AVAILABLE(_mac, _ios) AVAILABLE_MAC_OS_X_VERSION_##_mac##_AND_LATER

and then

#import <Cocoa/Cocoa.h>

in that order is important.

In the .pch file, <Cocoa/Cocoa.h> file internally imports <Foundation/Foundation.h> which inturn imports <Foundation/NSObjCRuntime.h> which contains the orignal macros that we are attempting to redefine. So why are we importing <Foundation/NSObjCRuntim.h> again on top? It is required because unless we import it before <Cocoa/Cocoa.h> and redefine the macros in question, the macro redefinitions won’t apply to the headers in <Cocoa/Cocoa.h> which is imported subsequently. As a result no warnings will get generated by Xcode at all. Hence the import of <Foundation/NSObjCRuntime.h>, redefinition, <Cocoa/Cocoa.h> in that order is important.

Ergo with the redefined macro replacements in place for the <Cocoa/Cocoa.h> that follows, any reference to new api symbols in your source code generates an Xcode warning. But why not make new api reference an error? The answer is that after factoring in the unavailability on older OS X versions, you may want to use the new apis conditionally and hence the warning mechanism seems like a better fit.

You may ask: What happens when we include <Foundation/NSObjCRuntime.h> explicitly and it get’s implicitly included in <Cocoa/Cocoa.h> as stated above? Well, that’s what the #import directive is there for. The #import directive ensures that a file is included only once no matter how many times you put the #import statement. So the <Foundation/NSObjCRuntime.h> in <Cocoa/Cocoa.h> gets ignored. StackOverflow has a nice post on this.

Redefining a macro the right way

There are two scenarios where a macro collision like situation arises:

  1. The one that we saw above. Just comment out the line #undef AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER in the above code snippet and Xcode starts throwing macro redefined warning.
  2. When macros with same name but different definitions start falling in the same namespace by virtue of an #import. Let’s say you define a macro mysupermacro in abc.m and in pqr.h with different definitions. If you import pqr.h in abc.m, you get a macro redefinition warning. If you ignore the warning, the later definition gets applied. If the namespaces don’t collide (say you don’t import pqr.h in abc.m but in xyz.m and use mysupermacro there), mysupermacro serves its purpose in their respective files according to its definitions.

To summarize, the order of #import can be important sometimes and this case is a good example. That’s it for now. Good Luck And Good Life!!!

iTunes Link Maker

You have burnt the midnight oil over the last few months and finally submitted your app to the Mac App Store. Apple has approved it. Now comes the time to embed your app’s App Store link into your product website. Enter iTunes Link Maker.

On iTunes Link Maker, search for your app by providing the right parameters. Your app should appear in the search results. Click on the “Mac App Link” and you can get the direct link to your app or a small/large embeddable html code for a button. The button assets are provided by Apple servers. Cool right!! Go ahead and use it on your product website.

I wanted the behavior on link click to open the app page on iTunes in the browser and also open the App Store app on Mac with the app details. The iTunes Link Maker link I got for my app

https://itunes.apple.com/in/app/expensetrack/id870188888?mt=12&uo=4

was just opening the app page in the browser but didn’t open the App Store app on Mac so I had to change it to

https://itunes.apple.com/in/app/expensetrack/id870188888?mt=12&ls=1

to get the desired behavior.

If you wish to add your app’s link in the app bundle before submitting to App Store for say “Rate Us” or “Write A Review” implementation etc., you can use the following code snippet in your app

[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:macappstore://itunes.apple.com/app/id870188888?mt=12]];

This code opens the app page in the App Store app. An app gets assigned an id (870188888) the moment you create it in the iTunesConnect portal.

Java Keytool and SSL

Keytool is a Java utility to manage a keystore (database) of private keys, certificate chains and trusted certificates. It is included in the Java distribution. Java Keytool stores the keys and certificates in what is called a keystore. A keystore is a password protected file that contains the private key and any certificates necessary to complete a chain of trust and establish the trustworthiness of the primary certificate (purchased SSL certificate). A single keystore can contain multiple private keys and their corresponding certificate chains.

Each certificate in a Java keystore is associated with a unique alias. When creating a Java keystore you will first create the .jks file that will initially only contain the private key. You will then generate a CSR and have a certificate generated from it. Then you will import the certificate to the keystore including any root and intermediate certificates. Java Keytool also contains several other functions that allow you to view the details of a certificate or list the certificates contained in a keystore or export a certificate.

Keytool primer

//List keystore contents
static-202:~ Sayeed$ keytool -list -keystore abc-keystore

//Import SSL certificate into keystore. Import should be in the order: root -> intermed -> primary
static-202:~ Sayeed$ keytool -import -alias root -keystore abc-keystore -trustcacerts -file gdroot-g2.crt
static-202:~ Sayeed$ keytool -import -alias intermed -keystore abc-keystore -trustcacerts -file gdig2.crt 
static-202:~ Sayeed$ keytool -import -alias abc -keystore abc-keystore -trustcacerts -file 4af931ac9e4c59.crt 

Note: The last import i.e. your SSL certificate import should have the same alias as the private key. Only then will it be mapped with the private key which is REQUIRED.

//Delete certificate from keystore
static-202:~ Sayeed$ keytool -delete -alias "root" -keystore abc-keystore

//Convert keystore from jks to pkcs12
static-202:~ Sayeed$ keytool -importkeystore -srckeystore abc-keystore -destkeystore abc-keystore.pcks -srcstoretype jks -deststoretype pkcs12

Note: The above command doesn’t work because pkcs12 keystores are only meant for certificate-private key pairs. Root and intermediates certificates in the jks keystore cannot be exported because their private keys are absent.

//Print certificate details
static-202:~ Sayeed$ keytool -printcert -file mydomain.crt

//Export certificate from keystore
static-202:~ Sayeed$ keytool -export -alias www.mycompany.com -file mydomain.crt -keystore abc-keystore

//View certificate chain
static-202:~ Sayeed$ openssl s_client -connect mycompany.com:443 -showcerts

Keytool commands for Creating and Importing

//Generate a Java keystore and key pair
static-202:~ Sayeed$ keytool -genkey -alias mydomain -keyalg RSA -keystore keystore.jks -keysize 2048

//Generate a certificate signing request (CSR) for an existing Java keystore
static-202:~ Sayeed$ keytool -certreq -alias mydomain -keystore keystore.jks -file mydomain.csr

//Import a root or intermediate CA certificate to an existing Java keystore
static-202:~ Sayeed$ keytool -import -trustcacerts -alias root -file Thawte.crt -keystore keystore.jks

//Import a signed primary certificate to an existing Java keystore
static-202:~ Sayeed$ keytool -import -trustcacerts -alias mydomain -file mydomain.crt -keystore keystore.jks

//Generate a keystore and self-signed certificate (see How to Create a Self Signed Certificate using Java Keytool for more info)
static-202:~ Sayeed$ keytool -genkey -keyalg RSA -alias selfsigned -keystore keystore.jks -storepass password -validity 360 -keysize 2048

Keytool commands for Checking

//Check a stand-alone certificate
static-202:~ Sayeed$ keytool -printcert -v -file mydomain.crt

//Check which certificates are in a Java keystore
static-202:~ Sayeed$ keytool -list -v -keystore keystore.jks

//Check a particular keystore entry using an alias
static-202:~ Sayeed$ keytool -list -v -keystore keystore.jks -alias mydomain

Other Keytool commands

//Delete a certificate from a Java Keytool keystore
static-202:~ Sayeed$ keytool -delete -alias mydomain -keystore keystore.jks

//Change a Java keystore password
static-202:~ Sayeed$ keytool -storepasswd -new new_storepass -keystore keystore.jks

//Export a certificate from a keystore
static-202:~ Sayeed$ keytool -export -alias mydomain -file mydomain.crt -keystore keystore.jks

//List Trusted CA Certs
static-202:~ Sayeed$ keytool -list -v -keystore $JAVA_HOME/jre/lib/security/cacerts

//Import New CA into Trusted Certs
static-202:~ Sayeed$ keytool -import -trustcacerts -file /path/to/ca/ca.pem -alias CA_ALIAS -keystore $JAVA_HOME/jre/lib/security/cacerts

Some Helpful OpenSSL commands (openssl installation required)

//Check csr
static-202:~ Sayeed$ openssl req -text -noout -verify -in abc.csr 

//Check certificate
static-202:~ Sayeed$ openssl x509 -in 4af931ac9e4c59.crt -text -noout 

For more information, check out the Java Keytool documentation.