sohail.io

  • About

AppleScript Export to CSV via iWork Numbers

October 24, 2015

Many of us have to consume reference data in our apps provided by clients, business analysts or other team members. We’re unlikely to have them give us a JSON file or an XML property list.

For structured data, I’ve found that setting up a spreadsheet for clients that I can later parse as a CSV file, works great.

Of course, having to open Microsoft Excel or Apple’s iWork Numbers program manually and go through all of the menu commands to perform an export can become tedious when you have a lot of files to process and/or there’s a high frequency with which you receive updates.

As developers, we know the solution to such tedium is to write code to automate these activities.

Fortunately, Apple has AppleScript support in Numbers that lets us get this done.

I’ve created a public Gist with such an AppleScript program that you’ll find helpful to export Excel or Numbers spreadsheets, into CSV documents.

The script is called SpreadsheetExportToCSV.scpt. You can invoke it from the command line as follows:

    osascript SpreadsheetExportToCSV.scpt <input file> <output file>

Here’s a more concrete example where my source file (assumed to have one worksheet in it) is specified, along with my output CSV file:

    osascript SpreadsheetExportToCSV.scpt "/Users/me/Documents/MySpreadsheet.xlsx" "/Users/me/Documents/Converted/OutputFile.csv"

I find it safer to always places quotation marks around the input and output file paths, so that any spaces or other special characters don’t need to be escaped.

Source

Here’s the script as currently posted in the GitHub Gist:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
 
#! /usr/bin/osascript
 
(*
---------------------------------------------------------------------------------
 
Script: SpreadsheetExportToCSV
 
Command-line tool to convert a spreadsheet document to CSV
This AppleScript is tested with and compatible with Apple iWork Numbers 3.6,
current as at October 23, 2015.
 
Parameters:
1. Full Path to the input file, including file extension
2. Full Path to the output file, including file extension
 
Example command-line invocation:
 
    osascript SpreadsheetExportToCSV.scpt "/Users/me/Documents/MySpreadsheet.xlsx" "/Users/me/Documents/Converted/OutputFile.csv"
 
The spreadsheet to use as an input file can be an Excel file or a Numbers file.
 
Sohail A.
Blog: http://sohail.io
Twitter: @idStar
 
Creation Date: October 23, 2015
---------------------------------------------------------------------------------
*)
 
global _inputFilePathAlias
global _outputFilePath
global _requestedOptions
 
 
(*
run
 
This is our entry point, our main function, where this script
begins execution. We call out to helper functions, to modularize
the design.
*)
on run argv
-- Ensure our CSV files are encoding with UTF8:
ensureUTF8Encoding()
-- Parse and determine input/output paths:
retrieveCommandLineArguments(argv)
-- Perform the actual activation, file open, export and cleanup:
processSpreadsheet()
end run
 
 
 
 
---------------------- SUPPORTING FUNCTIONS --------------------------
 
(*
retrieveCommandLineArguments
 
Handles parsing the command line arguments passed to us.
We return a list, where the first element is the input file
path as an alias. The second element is the output path,
as text (as it may not yet exist).
*)
on retrieveCommandLineArguments(command_line_arguments)
set _inputFilePathAlias to POSIX file (item 1 of command_line_arguments) as alias
set _outputFilePath to (POSIX file (item 2 of command_line_arguments)) as text
log "input file path is: " & _inputFilePathAlias
log "output file path is: " & _outputFilePath
end retrieveCommandLineArguments
 
 
(*
processSpreadsheet
 
This function is the workhorse of this script. We open Numbers,
have it load the source spreadsheet, and invoke the export command
to ultimately write the output CSV to the specified path.
*)
on processSpreadsheet()
tell application "Numbers"
activate
-- Before we open the file asked of us, close out every document
-- that might have opened along with the application having activated:
close every window saving no
-- Retrieve information about the source file:
set fileInfo to (info for (_inputFilePathAlias))
set fileName to name of (fileInfo)
set fileExtension to name extension of (fileInfo)
log "Opening source document " & fileName & "..."
tell (open _inputFilePathAlias)
-- In this scope, we are now implicitly dealing with the document just opened
-- as the current target, which means we access it through the "it" keyword,
-- as per: https://developer.apple.com/library/mac/documentation/AppleScript/Conceptual/AppleScriptLangGuide/conceptual/ASLR_fundamentals.html#//apple_ref/doc/uid/TP40000983-CH218-SW4
set activeDocument to it
-- Note: We could have also gotten to the active document by walking the chain from the top,
-- i.e. right from the Application object:
--set activeDocument to document 1 of application "Numbers"
say "Starting Export."
with timeout of 600 seconds
export activeDocument as CSV to file _outputFilePath
-- Use this instead if you want to export to Excel:
-- export activeDocument as Microsoft Excel to file _outputFilePath
end timeout
say "Completed Export."
-- Since we closed out other windows that might have been open before
-- opening the file we sought, we really should only have one document
-- window open.
close activeDocument
end tell
quit
end tell
end processSpreadsheet
 
 
(*
ensureUTF8Encoding
 
Microsoft Excel on the Mac is not good with exporting special
characters as is Apple Numbers. Part of this is in the ability for
Numbers to correctly process UTF8 formatting when exporting.
 
Setup default export encoding for CSV files to UTF8, so without
specifying anything further for AppleScript, the right format will
be applied automatically. Since we cannot specify the CSV export
encoding via AppleScript, we will set it via the Defaults Database
with a shell command.
Here are the codes that apply: 4=UTF8, 12=windows latin, 30=MacRoman
As such, we'll specify 4 for UTF8.
 
This technique courtesy of: https://discussions.apple.com/thread/4018778?tstart=0
*)
on ensureUTF8Encoding()
do shell script "/usr/bin/defaults write com.apple.iWork.Numbers CSVExportEncoding -int 4"
end ensureUTF8Encoding
 

Filed Under: General Tagged With: AppleScript, csv, Excel, gist, iWork, Numbers

Verifying the Status of an Auto-Renewable Subscription

October 19, 2015

There’s a growing trend of iOS apps offering auto-renewable subscriptions as their mode of generating In-App Purchase (IAP) revenue. I’ve recently implemented Auto-Renewable Subscriptions in a client’s universal iOS app, and have some lessons learned that I’d like to share in this post.

If you’re not familiar with Store Kit for In-App Purchases, Auto-Renewable Subscriptions or Receipt Validation, you’ll want to start with the Resources section at the end of this post.

During development of subscription functionality, I had recently run into an ambiguous situation regarding receipt validation. The problem encountered was fortunately caught in the early days of a soft launch.

In this post, my aim is to provide you with more clarity on receipt versioning than I had at the outset. Here, I’ll cover what to do when an app with an active subscription is updated from the App Store to a new version that you’ve released, and how to determine whether users have a subscription to your app using only the App Receipt.

The Lesson

There’s a lot of stock advice and sample code regarding receipt validation, but there’s a risk of putting it together wrong.

For example, if you’re dealing exclusively with iOS7 and later, an Auto-Renewable Subscription purchase can always be found in a valid and current App Receipt. But if you check the app’s bundle version against that in the App Receipt every time you need to verify subscription status, your subscribers will be locked out when they install a new app update that you’ve released.

This is because from my experience, the bundle version stored within an App Receipt is not updated to match the version of every app update that your users will install. Rather, the App Receipt retains the bundle version of the last app release through which the user most recently conducted a purchase.

I’ve not seen any tutorials or WWDC videos speak to under what conditions the version number in the receipt gets revised. Have you? If so, I’d love you to point fellow readers and myself to such material. Leave a comment or message me on Twitter.

Examples in written guides and videos seem to always talk about receipt validation in the context of having just made a purchase, where the bundle version of the app that just made the purchase and the bundle version retrieved from the receipt, will match up. Historically, developers have had to verify receipts and then store IAP information themselves.

If however, you are verifying the receipt as part of your mechanism to determine subscription status whenever your app launches because you don’t store that information anywhere else, then you should not insist on the bundle version matching as part of your receipt validation process.

Prevailing Examples

Whenever I’d see a tutorial on receipt validation, I’d almost always see the following three things being checked after the receipt is located and confirmed to be properly signed by Apple:

  1. The bundle identifier
  2. The bundle short version string
  3. The hash of the GUID

The Receipt Validation Programming Guide

Here’s the Validate the Receipt section of Apple’s official Receipt Validation Programming Guide:

To validate the receipt, perform the following tests, in order:

  1. Locate the receipt. If no receipt is present, validation fails.
  2. Verify that the receipt is properly signed by Apple. If it is not signed by Apple, validation fails.
  3. Verify that the bundle identifier in the receipt matches a hard-coded constant containing the CFBundleIdentifier value you expect in the Info.plist file. If they do not match, validation fails.
  4. Verify that the version identifier string in the receipt matches a hard-coded constant containing the CFBundleShortVersionString value you expect in the Info.plist file. If they do not match, validation fails.
  5. Compute the hash of the GUID as described in Compute the Hash of the GUID. If the result does not match the hash in the receipt, validation fails.

If all of the tests pass, validation passes.

This makes sense in that when a user makes a purchase, such as a subscription, the bundle version in the receipt that’s implicitly refreshed as part of the purchase will match the bundle version of the app currently running. IAP tutorials will often store purchase history in NSUserDefaults, to keep things simple. They also advise you to consider something more robust as a method of recording keeping.

You need to take security measures appropriate with the value of your IAPs, the user demographic you anticipate and the attack vectors you are keen on providing a defense against.

WWDC Sessions

In Session 308 at WWDC 2013 entitled Using Receipts to Protect Your Digital Sales, you can find advice to check the bundle version as part of your verification process. See the segment at time index [25:30] to about [27:00]. We’re also advised at time index [37:00] through [38:00] that Auto-Renewable Subscriptions are always in the App Receipt. And further, that you could restore transactions to verify the purchase.

What’s not covered is what exactly you would check in the App Receipt when attempting to verify a purchase. To me, if you check the bundle identifier and the hash of the GUID, leaving out the bundle version, you have verified the purchase. You can still check subscription expiry information without having to issue a restore transactions request.

To add another layer of security, you could store subscription status with the user’s counterpart account in the cloud, if your app extends beyond just the mobile device. However, if you only have an app where everything takes place on the device, I have found that relying on the App Receipt itself as the source of truth for Auto-Renewable Subscription status, works very well.

Oliver Drobnik’s Talk

The clearest information on this I’ve seen anyone call out, comes from the wise Oliver Drobnik who in his presentation iOS Subscriptions 2.0, provides guidance on this topic at time index [31:37] to [36:00]. Oliver specifically calls out that bundle versions may not match up, and so we wouldn’t always insist that they do when performing receipt validation in all cases.

Ideas for Improvement

What I’d like to see from Apple at a WWDC session, is explicit clarification on when the App Receipt bundle version is revved. I’ve since inferred this on my own through development, trial and error. However, I believe it’s worth an explicit mention.

At the outset, I had naively assumed that if the user had updated an app from the App Store, that their App Receipt would also get updated to reflect the current bundle version of the app build that they were now running.

If I were on the Store Kit team, I would have the App Receipt bundle version revved with every app update that the user downloaded, and store within the individual purchase entries, the bundle version associated with what was running on the user’s device at the time they had made that purchase. Regardless, this is all workable as currently designed once we understand the specifics about bundle version revisions in the App Receipt.

Auto-Renewable Subscription Stored in App Receipt

Assuming you’re dealing with a modern iOS app (iOS7 and later), you don’t actually need to store the user’s subscription status anywhere; you can simply retrieve it from the App Receipt. Auto-Renewable Subscription purchases are always present in the App Receipt.

Of course, if the user first purchased the app’s subscription on their iPhone and then later downloaded a copy on their iPad, you would need to provide the user with a Restore Subscription button somewhere, where your task would be to refresh the App Receipt. Once you do that however, you have your source of truth with you always, for determining subscription status.

Let’s say that on each app launch, you set a Boolean property somewhere that indicates whether the user has an active subscription or not. You can lazily set this property by checking the App Receipt.

Here’s what you do not want to do: Trigger a receipt refresh request each time the app launches or worse, every time your app checks whether the user has an active subscription in order to enable some content or functionality.

Once each device has an App Receipt that indicates the presence of the active subscription, you don’t need an Internet connection nor do you need to refresh the receipt each time you wish to check their subscription status. Instead, you follow the steps outlined above from the Receipt Validation Programming Guide, skipping Step 4.

The only time you want to include Step 4, is when you are validating the receipt right after having made a purchase. It’s only at this time that the version in the App Receipt and the version of your app, would be expected to match up.

Scenario 1: Verifying a Purchase Just Made

When your app successfully completes the purchase or renewal of a subscription, Store Kit will no doubt inform you by invoking the method:

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions

on your class that implements the SKPaymentTransactionObserver protocol. This is the time however, to actually look at the App Receipt that would have been updated on your user’s device, to verify that the App Receipt is valid, and that it actually contains the purchase just made. In this case, the Auto-Renewable Subscription.

It is in this scenario that you are going to include verifying the bundle version as part of the receipt verification process.

Verifying a purchase just made

What you do not want to do here, is use the above flow to attempt to restore an active subscription, possibly purchased on another device. If you do that, you risk failing receipt verification because the bundle version of the receipt you refresh and the bundle version of the app currently running, may not match up. 

Scenario 2: Checking Subscription Status

In this scenario, the user is not asking to purchase or renew a subscription. They are merely trying to access a part of your app that would require an active subscription, or you are checking to see if you should display some content that would only present, if the user had an active subscription.

At this juncture, what is important is that:

  1. You do not trigger a dialog requesting the user do something if they didn’t expressly interact with your UI. That means that you do not trigger a receipt refresh request unless the user did something explicit, like tap a ‘Restore Subscription’ button.
  2. If the user has a subscription, you should not need an Internet connection to verify this when you look to the purchase information found within the local App Receipt.
As you’ll see below, an app that follows this path for periodic subscription status checks can verify and parse the App Receipt almost instantly, without needing the Internet or pestering the user.
 
In this way, you do not need to have any additional system of record for a user’s Auto-Renewable Subscription status — you can retrieve it from the App Receipt whenever your app needs to know.
 

Checking subscription status

It’s at this juncture, that if the user attempts to do something for which they are missing a subscription, that you can offer to sell them an auto-renewing subscription. Additionally, you can offer to check if they have an active subscription that can be restored onto the current device. The later option is where you issue a refresh receipt request from the App Store, which will automatically trigger an App Store credentials request of the user.

Resources

Here are the promised resources mentioned at the start of this post.

Background

Note that only a fraction of apps are currently able to take advantage of auto-renewable subscriptions, given Apple’s App Store guidelines.1 However, there does seem to be an easing over the last few years of what qualifies.

With an Auto-Renewable Subscription, users are paying for ongoing new content or a service. Content may be episodic like a magazine, a database of media that can be streamed on demand or a constantly updated medical reference database. In the service category, think of apps like Evernote that allow subscribers to sync data with Evernote client apps on other platforms.

Videos and Tutorials

This post did not provide an introduction to IAP, Auto-Renewable subscriptions or Receipt Validation. For that, I’d suggest the following resources:

  1. Video: iOS Subscriptions 2.0. This is a presentation that Oliver Drobnik of Cocoanetics gave in October 2015. A great introduction and overall summary.
  2. Video: Managing Subscriptions with In-App Purchase. This is Session 308 from WWDC 2012. Explains the mechanics of subscriptions and their timelines.
  3. Video: Using Receipts to Protect Your Digital Sales. This is Session 308 from WWDC 2013. Covers the high level process of validating receipts on your device.
  4. Article: Receipt Validation. This is from Issue 17 of the highly acclaimed objc.io online publication.
  5. Guide: In App Purchase Programming. This is an official guide from Apple.

To learn the basics of Store Kit and obtain a gentle introduction to receipt validation, I’d recommend Chapter 9 (“Beginning In-App Purchases”) of iOS 6 by Tutorials,2 from the Ray Wenderlich tutorial team.

  1. Section 11.15 states: Apps may only use auto-renewing subscriptions for periodicals (newspapers, magazines), business Apps (enterprise, productivity, professional creative, cloud storage), and media Apps (video, audio, voice), or the App will be rejected [↩]
  2. Don’t be fooled by the “iOS6” in the title. The book has been updated to reflect changes in any related API inclusive of iOS8, and all of that works just fine for StoreKit with iOS9. The iOS version number in the book title reflects the iOS version the contained topics were first introduced by Apple, or for when said topics underwent major changes [↩]

Filed Under: iOS Tagged With: auto-renewable, bundle version, receipt, refresh, subscriptions, validation

Swift Memory Management Exercise

June 21, 2015

I’ve covered my approach to learning Swift in an earlier post.

In this post, I wanted to post my solution to an exercise in the Intermediate Swift Tutorial Series video for Memory Management (Part 9), available at RayWenderlich.com. Note that you’ll need to be a paying subscriber to access the video tutorial page.

The exercise challenges the reader to create an object graph avoiding retain cycles, noting that Swift Array objects, like in many reference counted languages, will have strong references to all of their elements.

You’ll need to review the actual tutorial challenge for context (that’s copyright material I won’t reproduce here). However, if you’ve followed along, you’ll know that the posted solution playground doesn’t actually demonstrate or prove to the reader that there are no retain cycles.

As such, I set out to answer the exercise in a way that would give me that tangible satisfaction that the full object graph had gotten deallocated.

You can access the full contents of my solution playground from this gist.

As you can see below, when I set the rwDevCon variable to nil, it sets off the chain of visible deallocation. 

You can also download a zip archive of the Xcode 7 Beta 1 playground that I used to complete the exercise from the Ray Wenderlich tutorial here: MyLearningPart09.playground.zip

My Solution to the Memory Management Exercise

Filed Under: iOS Tagged With: arrays, memory management, optionals, raywenderlich.com, retain cycles, swift, weak

Learning Swift: My Approach

June 21, 2015

With the announcement of Swift 2.0 at WWDC2015, I’ve finally taken the plunge to set aside a few days and actually learn Swift. I’m not mixing Swift with production Objective-C anytime soon, but I’ve found that code snippets on the web, tutorials and even Apple’s WWDC videos are becoming increasingly difficult to follow (and fully comprehend) without at least knowing the basics of Swift.

On the path to acquiring this knowledge, I’m going through a few resources in parallel.

Book: The Swift Programming Language

Apple’s The Swift Programming Language book throws you into Swift coding in the first chapter (“A Swift Tour”), which is a quick preview through many key aspects of the language. Fear not, the next chapter is the start of the Language Guide, which slows down the pace and covers the concepts in more depth.

I’ve been making my way through the new pre-release version covering Swift 2.0, and using Xcode 7 Beta 1 for all exercises in the book as well as those found in other resources.

Videos: WWDC 2014 and 2015

I’m a completionist, and so given that WWDC sessions often build upon successive years, I started back with the 2014 sessions. Anything with the word “Swift” in the title would get watched. That means beyond just the language itself, I’d cover playgrounds and interoperability with Objective-C.

You can watch Apple’s WWDC2014 and WWDC2015 Swift videos online, or through the WWDC iOS app.

The benefit of starting back at 2014 is that I can see what changed. I know that println used to be a thing, but that now it is just print  This helps me navigate the myriad tutorials and snippets of code online, without being bewildered about what I might have missed. I do believe this will actually save me more time in the long run.

Blog: Apple’s Official Swift Blog

Apple’s Official Swift Blog is a refreshingly candid and helpful peak inside the minds of Swift’s creators and stewards. I’m starting from the beginning, and progressing as the other resources give me the needed foundations to fully appreciate. I stop whenever I get to a post that talks about concepts of Swift I’ve not yet covered elsewhere.

I then revisit when I’ve learned more.

Ray Wenderlich’s Swift Tutorial Video Series

This is where I spend most of my time of late. In addition to the video series, there are some great written articles you’ll find as additional resources.

Here’s where you’ll find the Swift video tutorial series with Brian Moakley that I’m going through presently. Watch each video and then do the exercise(s). Struggle with it. Search through API docs to think about how you would solve various challenges when you need more inspiration.

This is where the learning is really solidifying for me. If I had to pick one resource, it would be this one. But of course, neither you nor I need to take such drastic measures, so supplement with all of the above!

Note that you need to be a paying subscriber to raywenderlich.com to watch these videos. If you develop iOS software for part or all of your income however, this meager subscription fee should be a no brainer. It is extremely cost effective and the material is very well produced.

Whenever I’ve needed to bring on iOS developers to augment an existing project team, I’ve always directed folks to RayWenderlich.com and the excellent iOS by Tutorials series to make sure everyone knows how to use the new APIs each year. It’s important to adopt the new APIs because they build on each other.

Folks who refused to adopt Auto Layout, Size Classes and Adaptive Layout are now going to have a hard time supporting side-by-side multitasking on iPad in iOS9.

As an experienced developer, I look to the resources on RayWenderlich.com to keep up to date. It’s not just for beginners or intermediates. In fact, for very experienced developers, it’s still the fastest way to get up to speed on the new frameworks and APIs.

But I digress! And no, Ray Wenderlich didn’t pay me anything to praise their material!

 

Filed Under: iOS Tagged With: exercise, raywenderlich.com, swift, tutorial

UIAutomation Command Line Test Runner for Xcode 6

September 20, 2014

UIAutomation tests for iOS apps are a great way to test an app’s user interface and interaction in a way that traditional unit tests for iOS apps cannot. That said, building them right takes a considerable investment in time. Invariably, you’re building upon the primitives that Apple has provided with their UIA JavaScript classes.

Running UIAutomation scripts through the Instruments GUI can be tedious; especially when you’re in a heavy develop-run-test workflow. Fortunately, Apple has given us a way to run the Automation Instrument through the command line. Apple’s documentation on Automating UI Testing is however, brief.

The section of Apple’s documentation that concerns us is entitled Executing an Automation Instrument Script from the Command Line. Unfortunately, at the time of this writing, the information in that section of Apple’s documentation still had errors when iOS8 went public.1.

You might have read that the -w <deviceID> switch was optional if you wanted to run in the simulator.

That was likely true in the past, but no longer with Xcode 6.0.1. You now need to provide the symbolic name of the simulator you wish to run your app in.

Additionally, the documentation suggests that you can find the Automation Instrument template at the following outdated path:

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/ Instruments/PlugIns/AutomationInstrument.bundle/Contents/Resources/Automation.tracetemplate

With Xcode 6.0.1, the path to the Automation Instrument template is now:

/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns/ AutomationInstrument.xrplugin/Contents/Resources/Automation.tracetemplate

While these paths have been known to change with various Xcode releases, what’s really tedious with command line invocation of UIAutomation tests is the fact that you have to provide the path to the app in the simulator. That path has a UDID for the simulator in it, and a GUID for the application itself. Presumably this mimics some of the internal organization used on the devices themselves.

In any event, when you reconfigure your defined simulators in the updated iOS Simulator app, those simulator UDIDs are going to change. When you clean out your build folders with a sledgehammer and restart fresh, those GUIDs for your apps are likely going to change too. Hard coding references to such in your test script runner would be annoying.

It’s with that motivation that I wrote a couple of scripts to encapsulate all of this minutia, and abstract it for us developers who understand how it works, but don’t want to get lost in the weeds every time something changes.

UI Automation Runner

The ui_automation_runner.sh script I developed can be found in this UI Automation Runner project. The project’s README file covers the basics.

The benefit to using such a script is that it is focused on one thing: running your automation tests. It doesn’t pretend to build or install your apps. There are so many more complex tools that run UIAutomation scripts and do a whole lot more at the same time. I was hard pressed to find something nimble with the singular purpose of just running a single UIAutomation test.

When paths for the Automation Instrument change with a future Xcode release, or the default home for simulators changes, you can go ahead and edit these two lines in the ui_automation_runner.sh script, assuming you know what you’re doing. And if you beat me to it, send me a pull request and I’ll update it for everyone.

1
2
3
4
5
6
7
8
9
10
11
12
 
# ---------- DO NOT EDIT ANYTHING BELOW THIS LINE, UNLESS YOU KNOW WHAT YOU'RE DOING -----------
 
# ===== GLOBAL CONSTANTS =====
# This is where Xcode installs simulators. Accurate as at Xcode 6.0.1.
BASE_SIMULATORS_PATH="$HOME/Library/Developer/CoreSimulator/Devices"
 
 
# UIAutomation Instruments Template location. Accurate as at Xcode 6.0.1.
INSTRUMENTS_AUTOMATION_TEMPLATE_PATH="/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents"\
"/PlugIns/AutomationInstrument.xrplugin/Contents/Resources/Automation.tracetemplate" # DO NOT CHANGE INDENTATION!
 

You should construct your UIAutomation tests so that the one test file you pass to the command line for invocation, ends up running your entire JavaScript test suite.

To use this project, you’ll actually leave the ui_automation_runner.sh script file untouched. Instead, you’ll change the settings in the companion run_tests.sh script that then invokes the ui_automation_runner.sh script which in turn, intelligently invokes Apple’s own instruments command.

Here’s the script that you need to customize. As you can see, it’s reasonably clear where you provide the details for your specific app, simulator, test file and paths.2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
 
#!/bin/bash
 
# run_tests.sh
# Created by Sohail A.
# @idStar
 
# This script is a companion to the script ui_automation_runner.sh, which is designed not to be edited.
# In this very script however, you'll actually modify some variables below to specify values for
# what you would like run, where to find your test, where to dump results, etc.
 
 
# ===== DEVICES AND SIMULATORS =====
 
# Define all of your simulators and devices here.
 
# Create descriptive variables to hold the UDIDs of your devices and the custom names of your simulators.
# If you're new to Xcode 6's custom simulators, read the following for more context:
# https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/iOS_Simulator_Guide/GettingStartedwithiOSStimulator/GettingStartedwithiOSStimulator.html
# Specifically, the section entitled, "Change the Simulated Device and iOS Version". In a nutshell, you can to choose
# which simulators are defined, and what they're called. The ui-automation-runner.sh script will use these names
# to find the right simulator to launch. We recommend creating a variable for each of your defined simulators here,
# so you can switch between them easily when providing a value to the 'SIMULATOR_NAME_OR_DEVICE_UDID' down below.
 
device_udid_iPhone5s_iOS8="f04d9cefeccf5013e3ce89db955e68d6ce1551c4" # Not my real device UDID, but you get the idea
simulator_iPhone6Plus_iOS8="iPhone 6 Plus"
simulator_iPad_Air_iOS8="iPad Air"
simulator_iPhone5s_iOS7_1="iPhone 5s (iOS7.1)"
 
 
# ===== REACHING THE TEST RUNNER =====
 
# You may choose to keep this app specific script co-located with your app, and your copy of the
# ui_automation_runner script in some other more generic location. Whatever you choose, that needs to be reflected
# as an absolute or relative path to the current file:
AUTOMATION_RUNNER_SCRIPT_PATH="./ui_automation_runner.sh"
 
 
# ===== YOUR APP AND TEST FILE SETTINGS =====
 
# The name of your app. Use your Xcode project name. This is not necessarily the icon display name visible in Springboard.
# Leave off the ".app" extension so that you can reference the same app name when switching between device and simulator.
TEST_APP_NAME="ACMERoadRunnerRadar"
 
# Set which simulator or device you want Instruments Automation to run with:
SIMULATOR_NAME_OR_DEVICE_UDID=${simulator_iPhone5s_iOS7_1}
 
# The directory in which we can find the test file you'll specify below:
JAVASCRIPT_TEST_FILES_DIRECTORY="$HOME/Developer/clients/acme/roadrunnerradar/ACMERoadRunnerRadarAutomationTests/"
 
# The JavaScript test file you'd like to run. For a suite of tests, have this file simply import and
# execute other JavaScript tests, so that you can conceivably run a full suite of tests with one command:
JAVASCRIPT_TEST_FILE="TestRunner.js"
 
# The directory into which the instruments command line tool should dump its verbose output:
TEST_RESULTS_OUTPUT_PATH="$HOME/Developer/clients/acme/roadrunnerradar/ACMERoadRunnerRadarAutomationTests/TestRuns/"
 
 
 
# ---------- DO NOT EDIT ANYTHING BELOW THIS LINE, UNLESS YOU KNOW WHAT YOU'RE DOING -----------
 
"$AUTOMATION_RUNNER_SCRIPT_PATH" \
    "$SIMULATOR_NAME_OR_DEVICE_UDID" \
    "$TEST_APP_NAME" \
    "$JAVASCRIPT_TEST_FILE" \
    "$JAVASCRIPT_TEST_FILES_DIRECTORY" \
    "$TEST_RESULTS_OUTPUT_PATH"
 

Here’s what a sample invocation looks like:3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
sohail@103:~/Developer/clients/acme/roadrunnerradar/ACMERoadRunnerRadarAutomationTests master$ run_tests.sh
Instruments UIAutomation command invoked:
 
instruments -w 'iPhone 5s' \
-t '/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns/AutomationInstrument.xrplugin/Contents/Resources/Automation.tracetemplate' \
'/Users/sohail/Library/Developer/CoreSimulator/Devices/7232A640-A9D2-4626-A2AD-37AFFF706718/data/Containers/Bundle/Application/E71B915E-051D-4BEF-9083-34416D02EC91/RoadRunnerRadar.app' \
-e UIASCRIPT '/Users/sohail/Developer/clients/acme/roadrunnerradar/ACMERoadRunnerRadarAutomationTests/TestRunner.js' \
-e UIARESULTSPATH '/Users/sohail/Developer/clients/acme/roadrunnerradar/ACMERoadRunnerRadarAutomationTests/TestResults/'
 
2014-09-20 21:15:21 +0000 Start: Slingshot Apparatus Install
.
.
.
 

  1. Apple’s documentation was timestamped September 17, 2014. Of course, I’ve submitted feedback to Apple for each of the documentation errors I cite in this article. [↩]
  2. If you’re serious about reading this file line by line, you’d find it easier to read on GitHub itself. [↩]
  3. I’ve truncated the output after the first test logs that it started. The output can get quite verbose. [↩]

Filed Under: iOS Tagged With: command-line, script, test-runner, testing, uiautomation, xcode6

iOS7 UITableViewCell and the Covered Delete Button

October 21, 2013

Although iOS7 has encouraged less chrome in our user interfaces, some of us still find background views on table cells relevant. A bug in iOS7 (present at the time this post was written) inadvertently covers up the stock Delete button on a table cell if you have a backgroundView set on the table cell.

Initially, you see the Delete button and then the backgroundView slides over to the right to completely cover it!

An illustration of the problem

Many have reported this problem, such as this example from stackoverflow.com.

[Read more…]

Filed Under: iOS Tagged With: background view, delete button, iOS7, table cell

iOS7 View Controller Transitioning without Frames

October 20, 2013

View Controller Transitioning was introduced with iOS7. Previously, the out-of-the-box tools had developers relying on UIKit container controllers such as UINavigationController and UITabBarController to switch between view controllers.

Of course, there was always modal presentation of view controllers available and some basic transitions styles, such as sliding up from the bottom or flipping along the y-axis. In iOS5, View Controller Containers were made available. This finally provided some real structure to custom view transitions for view controllers.

If your app doesn’t require explicit container controllers however, I would argue that the new iOS7 API for View Controller Transitioning is simpler. In fact, if you want interactive transitions, then the choice becomes even more clear in favor of the View Controller Transitioning API. 

View Controller Transitioning is very much related to Container View Controllers, though we are only exposed to the container view concept in the Transitioning API. We don’t have to add and remove child view controllers as we would with full-on view controller containment approaches. In many ways, this makes a custom transition between two view controllers simpler to code.

This article discusses the use of the UIViewControllerContextTransitioning protocol’s methods for retrieving final frames for view controllers participating in the transition and how this API can be problematic. This article’s suggested approach is to rely on transforms instead. The majority of this article walks through how an animated translation transform can be used to implement a modal transition. This is still useful because the stock modal transition does not support keeping the ‘from’ view controller on screen, which is crucial if you want to create a translucent effect (useful should you decide on replacing the stock UIActionSheet or UIAlertView components).

For a proper introduction to this topic, see the WWDC 2013 video for session 218: Custom Transitions Using View Controllers.

[Read more…]

Filed Under: iOS Tagged With: auto-layout, iOS7, transitioning, view controllers

Welcome

October 19, 2013

As technical professionals, most of us feel that blogging is something that we ought to do.

My past writings from older blog platforms have now been re-launched on my personal blog, idStar.org. However, this blog site that you’re currently on will be for my professional writing on software development topics. Namely, iOS development.

In many ways, by blogging, we obtain the oft-cited benefits of journaling, except that the content is geared toward public consumption.

In the past few years, I have had several moments where I’ve paused and wanted to write about something going on in the iOS developer community or share some knowledge that I’ve learned tackling a development problem.

I kept putting these opportunities off, because I didn’t feel like I had a place to put them that was worthy of the investment I would want to make in such blog posts.

And this effort was always going to take place after I released the app my design partner and I are working on, since that took priority.

However, I finally decided this week, to no longer defer it. Diving into WordPress, widgets, premium themes and plugins took some time, but I’m glad I did it.

No doubt, I should have just done this years ago.

Now that I have this altogether and ready for when inspiration strikes, I am actually quite excited.

And with that, welcome.

Filed Under: General Tagged With: blogging

search

Categories

  • General
  • iOS

Recent Posts

  • AppleScript Export to CSV via iWork Numbers
  • Verifying the Status of an Auto-Renewable Subscription
  • Swift Memory Management Exercise
  • Learning Swift: My Approach
  • UIAutomation Command Line Test Runner for Xcode 6

This Blog

My name is Sohail. I'm a developer-consultant and entrepreneur primarily focused on building high quality iOS apps.

I write about software development. Mostly iOS related and sometimes, Ruby on Rails.

See the About page for more bio.

Sohail Ahmed - About page for blog author bio

Category Specific RSS

  • General (2)
  • iOS (6)

Archives

  • October 2015 (2)
  • June 2015 (2)
  • September 2014 (1)
  • October 2013 (3)

Copyright © 2021 Sohail A. · Log in

All opinions expressed are strictly those of the author, and do not necessarily reflect those of guests, partners, sponsors, customers or affiliates.