Menu

A lot of organizations out there want to make corproate-generated content living on their network available to users on their mobile devices. DocLink makes this possible without the headache of moving data to the cloud or other servers.

Check out this quick video describing how DocLink makes this possible:

I wrote a blog a little while ago about the subtle differences of location services between iOS 6, iOS 7.0 and iOS 7.1. Basically, there was a big change made in iOS 7.0 that caught many apps by surprise, and iOS 7.1 restored iOS 6.x behavior.

It looks like iOS 8 is maintaining parity with iOS 7.1, but we are still in the beta so I’ll be tracking it…

It is such a smart way to handle an otherwise annoying task of having to unlock your computer every time it locks. I’m a huge fan of credential-less / multi-factor authentication, and this product was the first one in quite some time that got me really excited (I think the initial “magic” of Dropbox was the last thing that wowed in the same way).

Then I got bummed out when I realized I didn’t have a supported Mac. Since Knock utilizes BTLE (BlueTooth Low Energy) 4.0, my 2008 Mac Pro didn’t have the goods built-in. I tried out Knock on my supported 2012 Mac Book Pro, and after seeing it work great, I was determined to get it working on my Mac Pro.

I’m happy to report, I got it working like a charm (care of a minor additional purchase). Here is how I got it to work.

Supporting Knock on a Older Mac

The good news is getting this working wasn’t very hard. Before I get into it, here are some prerequisites that I think you need to fulfill for this to work:

Mac OS X 10.9 or later (I think this may work on 10.8.x, but I have no idea. 10.9 is free and works great, so you really don’t have a reason to not upgrade anyway)

A relatively recent Mac. I got this working on a “Early 2008 Mac Pro” with 2×2.8Ghz Quad-Core Xeon processors. Although I cannot say for sure, if your system can support 10.9, I’m pretty sure you’ll be good to go hardware-wise

So, the key to making this thing work? A Bluetooth 4.0 USB donglethat is supported by OS X. Note that most USB dongles won’t actually say they support Mac, even ones that do. To that end, there are many (more) Bluetooth dongles that say they don’t support Mac and in fact do not!

Therefore, I will only recommend the USB dongle I got working on my Mac: the IOGEAR Bluetooth 4.0 USB Micro Adapter (GBU521) (Amazon Link). Of paramount importance is the “GBU521″ model, for reasons I explain below. At the time of this writing, the thing cost about $12 + shipping and taxes.

This specific model of the adapter is explicitly supported by OS X out of the box. Saving too many technical details, I have found that OS X explicitly calls out this adapter’s Bluetooth product and vendor ID in the system’s IOBluetoothFamily.kext driver in a way that makes it recognized by the system to work not only with Knock but all of your other Bluetooth peripherals as well. Good times!

So, after ordering the adapter, and before plugging it in, there are a few things you have to do. Keep in mind you are going to have to re-pair your keyboard and mouse, so plan accordingly.

Turn off bluetooth. Do this through the Menu Bar or in the Bluetooth System Preferences pane. Your existing bluetooth stuff stops working.

Plug-in the new adapter into any available USB port (I attached mine to a port under my wired keyboard). (The Knock app may or may not launch and show the “fire it up” screen).

If you don’t see the above screen, launch or quit/relaunch the Knock application on your mac. It should come up and you should no longer see the “unsupported mac” screen.

Wait at least 10 seconds, then turn Bluetooth On again.

Launch the Knock app. If all goes well, you should see a screen telling you to lock your iPhone, at which point you are paired!

Re-pair your other bluetooth devices (which are now connected using BTLE by the way) and you are good to go.

Please share and add a comment if these steps worked for you (or not).

Troubleshooting

Although this should all largely work, I did have some problems while writing these steps (the second time around; the first time worked perfectly). I was seeing things like “iPhone” flashing in my bluetooth menu, and the mac Knock app wasn’t recognizing my phone. I ended up deleting the device entry from the Bluetooth preference pane, and disabled and re-enabled bluetooth on my phone. Immediately after doing that, the phone connected properly and paired with Knock as expected.

If things really are going sideways, and you are a developer, there are a suite of Bluetooth tools available from the Apple Developer website called “Xcode Hardware IO Tools – Oct 2013″. In there you can look at logging and see what may be going on (but I’m not going to cover that here!).

Added steps to import the app’s Distribution Identity into the Xcode Server keychain

Fixed problem with Post-Action archive script that would post n-1 versions of the build to TestFlight

This kind of post represents why I started this blog: I spent days banging my head against the wall trying to get this all working, and no one else should have to endure the same.

This post outlines the major steps and gotchas surrounding how to:

Create a Bot that fetches source from a 3rd party Git repository

Builds, tests, and archives a project successfully

Automagically post an fresh build to TestFlight for automatic distribution every day to testers (this is as cool as it sounds)

Here are some prerequisites to consider:

You have OS X 10.9 with OS X Server installed.

I used a dedicated Mac Mini; so you may need to translate accordingly if you are using your local machine (though I don’t really recommend it).

You are familiar enough with provisioning profiles to be dangerous.

You have a working 3rd part git repository set up for your workspace. I’m using Assembla, but it should all be about the same with github, etc.

You have a TestFlight account and you know how to use it.

I will be using our Unwired DocLink product, a universal iOS content distribution app, as the model for this post.

As a disclaimer: this is all working for me… I did a lot of head banging and tweaking things to get stuff to work, most if not all of which is described here. Some stuff should have just “worked”, but didn’t at the time of this writing. I would like to keep this article updated if I missed something, so please post your comments below so I can update this article as needed.

And here we go!

Setting up Xcode

First up, you need to do some config with Xcode.

Create a new Build Configuration

Before you create a new scheme, you may want to set up a new Build Configuration. Projects created with Xcode come ready out of the box with Debug and Release builds. I create a duplicate of Release and named it TestFlight. You do this in the Project info screen as shown here:

Create a new build configuration named TestFlight

Next you are going to want to configure your distribution provisioning profile for the build you just made. It is helpful to filter the list down using the search bar at the top. I am using an enterprise distribution certificate, but you can specify an AdHoc one here as well.

Setting the Provisioning Profile

Keep in mind you will need to make sure all of your other build settings are correct as well, including making sure the correct code signing identity is specified in the build settings as well.

Create a new Scheme

You need to create a scheme that your Bot will use. You could technically use your default one, but to keep things a little cleaner, I created a new one. Simply create a duplicate scheme of your working one using the gear in the lower-right of the Manage Schemes window.

Create a Duplicate Scheme

Name the scheme something like “<ProjectName>_CI”. I would avoid white space (unlike my example) because things get a little hairy with paths later and that is one less thing to worry about.

With the newly created Scheme, make sure to check the “Shared” checkbox.

Highlight your newly created scheme and click Edit…

In this window, everything is likely fine by default with the exception of the Archive build configuration. There are a few things to do there, which needs its own section!

Configuring the Archive Scheme Build Process

There are two things you need to do here: configure the proper Build Configuration and specify your TestFlight deployment script.

First, make sure the Archive build configuration is set to TestFlight; the configuration you had just created.

Archive Build Configuration

And now here is where things get fun! Click on “Post-actions”, and if nothing is in there, click the ‘+’ at the bottom to create a “New Run Shell Script” action.

Below is the script you should use and substitute your values as needed. An explanation of important aspects of it are explained afterwards.

Whew! There are a lot of little nuggets in there worth explaining:

UPDATE: My original script used a “/Latest” symbolic link that the Bot would create, however this is created AFTER the integration has completed. Therefore, your builds that were uploaded to TestFlight were version-1. By using the ‘ls’ command, you effectively get the working script. Tangentially, the Archive.xcarchive.zip file does NOT exist at Post-Action time, but the folder does exist. The above script reflects both of these updates.

Your signing identity is the name of the certificate / key in your Keychain. It should be an EXACT string match, as shown in my Keychain.

Distribution Identity Name

You’ll notice some hard-coded paths. These are some of the paths used by the Xcode build server that don’t exist on your normal workstation. Some of these paths have been painfully crafted to make work after lots of head-banging.

The /tmp folder is used as a working directory to do intermediary work. It is cleaned up every time a build is performed.

This is all working as of the very first GA release of the Xcode Server; later releases may change paths that would require modification to the above script.

Make sure your build is sane

With the newly created scheme selected (next to the run and stop button in Xcode), select iOS Device (or any connected device) and go to the Product menu and select Archive.

Make sure the archive process works, because if it doesn’t work on your development station, it sure as hell isn’t going to work on the Xcode server :). The TestFlight upload process will fail because the specified directories don’t exist on your local machine (unless the Xcode server is on the same machine). However, Xcode should open organizer and a new TestFlight release build should be available as you would expect.

If so, commit your project changes to your git repository. The Xcode server will need all of those settings we just changed in the project file to work correctly.

If you get build errors, Google is your friend. There are simply too many build configuration problems to try explain here. Once you get it working, however, read on!

Prep the Xcode Server

If you haven’t already, make sure you have the Xcode Server running on your Mac OS X server. That set up is pretty straightforward.

There is no need to create any repositories here! That will be handled when you create the bot on your workstation.

However, do make sure you allow HTTPS access to repositories:

Repo Settings

Installing Distribution Provisioning Profiles

In theory, at this point you should be done. However, at the time of this writing, essential distribution provisioning profiles are not installed when you configure teams in Xcode server. This means your Xcode server has no way of properly signing your app, resulting in build errors time and time again during the archive phase.

This means you have to manually download the .mobileprovision file(s) and move it/them to the appropriate location on the server. The good news is this is pretty easy.

You have to run the copy using sudo, because of tight permissions on the folder. That said, there is no need to change permissions.

Installing Your Distribution Identity into the Keychain

Another thing the Xcode server doesn’t (can’t?) do is post your app’s iPhone Distribution identity (certificate and key) into the keychain of the Xcode server itself. Remember that this Distribution Certificate (aka Signing Identity) is tied to your Distribution ProvisioningProfile. Without this, your app will not compile and you’ll get an error like this:

With Xcode 5, the Distribution Identity is created through Xcode automatically when you are the agent for the account and a Distribution Certificate doesn’t yet exist. If one already exists, and it isn’t in your keychain already (see below), you may have to either a) manually download the certificate from the iOS Developers portal or b) hunt down the person who has the identity and have them send it to you.

All that said, here are the steps to extract the Distribution Identity from your development machine’s keychain (assuming it was created there), and transported to your Xcode server.

First up, open the Keychain app on your development computer. Select the login keychain and then click My Certificates under categories. In the Search field, type “iPhone Distribution” and you will see your distribution certificates float to the top:

Locating your Distribution Certs

Now a key (pun kinda intended) thing here: make sure you have the little arrow to the left of the name of the certificate. If you do NOT have it, then you DO NOT have the private key for the distribution certificate and things are not going to work (this means you have the certificate, but not the identity). You will need to find the person/computer that DOES have this private key and perform this task from there.

Now, with the arrow opened or closed (I opened it to show you the key, your may be named different) right-click the certificate row and select Export. From there, provide a strong password and save the resulting .p12 file somewhere on your hard drive.

Export the Identity

Note that sometimes the Export option doesn’t show up (at least in OS X prior to 10.9, it may have been fixed). Simply toggle the arrow, click on something else and back, etc. and it should then show up).

At this point, the .p12 should have been saved where you specified. Now transfer it to the Xcode server using your file transfer method of choice: SSH, AirDrop, FTP, GOPHER… whatever floats your boat.

On the Xcode server, locate the transferred .p12 file and drag-n-drop it onto of the Keychain Access app (/Applications/Utilities). You will be presented with a dialog to import the certificate. Select the system keychain then click Add. Provide the strong password you created when exporting the .p12 file, and if all goes well, you will see the identity in System -> My Certificates.

Import the Identity

Guess what, your Xcode Server now has what it needs to build archives for your app!

Creating the Bot

Alright, now this is where things are a little weirder than you would expect them to be.

In my case, I use SSH to access my git repository. However, I cannot for the life of me get Bots configured with SSH to properly pull from the repository. It may be an Assembla thing, but despite my best efforts, I cannot get it working. Instead, I use HTTPS (with username and password) to access the source.

Now here is a weird thing (that may be fixed in a later release). You can only create a Bot using the same git mechanism you have configured for your current workspace! This means that since I am using SSH to access my repo, the only auth form I can use when creating a bot is with SSH (there is no option to switch to HTTPS).

If you can get SSH authentication to work properly on your Xcode server with the specified repo, please share! Otherwise, I am going to assume you will do this HTTPS workaround like I did.

So, how do you use HTTPS? Checkout your project into another folder using HTTPS. You only need to use this for the bot setup, then you can delete this copy from your development machine because the server will now have all it needs to properly authenticate.

In my case, I closed out of my DocLink workspace and basically checked out the same workspace using HTTPS instead of SSH on a different folder on my HD. You can use the Check Out option within Xcode (and create the Repository entry via HTTPS there), or you can checkout via command line. Either way, when you are done you should be looking at an identical copy of your workspace, only using HTTPS with your source control.

Great, now lets create that bot!

The Bot Wizard

Go to the Product Menu and select Create Bot…

In there, you are going to want to make sure to select the new scheme you had made. If it is complaining about not having the shared scheme, make sure you had checked the “Shared” checkbox in the Manage Schemes window and committed your changes to the git repo.

Your Xcode server should appear in the Server list, or you may need to create the server entry first from the menu.

Check the Integrate Immediately so a test run can complete and we can see what is going on.

Initial Bot Config

Click Next.

You may be prompted for your git credentials next (this may be out of order; I’m not going to break my build for the sake of this post, sorry :). When you are, complete the form as appropriate:

Assembla Repo Config and Auth

Click Next.

You can schedule the bot to run whenever you’d like, but I would recommend once a day. The reason being is that you can quickly end up with TONS of TestFlight builds if you have the bot run on every commit, making it somewhat challenging. I run at 3:00am daily, so testers have a new version to work with in the morning.

Bot Schedule Config

Now for another painful lesson that will probably be fixed in a later release: there may be multiple iOS simulators for a give form factor, but not all of them work… This turns into a bit of a guess gaming (you can change these settings after bot creation through the Xcode Server’s website), but rest assured, your tests won’t run if you specify this wrong. So, in short, do not select all iOS Simulators or Devices if you have duplicate entries when selecting Specified Devices. Below is the screenshot of the multiple entries. It seems like the copies lower in the list are the ones that work, though they are shown differently in the Bots Settings via the Xcode server website, so I can’t say for sure.

Device Selection

On the next screen, set up notification options to your preference. Then click Create Bot.

If all goes well, you get a nice big green checkmark! Bot created!

Verifying the Integration

Now we’ll want to make sure things worked alright (if you are lucky, the will!)

Use the Xcode Server website. Usually it is just your machines root URL (e.g. http://ci.unwiredrev.com for our machine). You will see a screen like this (though maybe not with everything because you may not have run successfully before):

Xcode Bots Webpage

It should show “Getting Sources” or “Integrating”.

Clicking on a Bot’s name will reveal details. After some time of things working well, you should see something like this:

Bot Status Details Screen

You can see where things were not working so well…

When an integration is done, it should show completed for the most recent integration, ideally without any errors.

The “Logs” tab is really useful, as it give full logging details for each integration. Our TestFlight script actually writes out to this log during integration, so any errors with the upload show show there. Below is an example of a successful TestFlight upload:

Build Logs with TestFlight Upload Success

I’ve found Sometimes builds will fail for no reason. Rebooting the server has fixed this a few times for me… This was during the beta period, and may not be a problem now.

You also may want to disable Testing and Analyzing while you are figuring this out (in Bot Settings) to save time on the integrations just to make sure the archive is posted to TF correctly.

I think that’s about it! I’ll update this post as I receive feedback, so please comment if this process has worked for you or not. Good luck!

For us folks dealing with enterprise mobility and MDM, having access to the iOS Unique Device Identifier (UDID) in our apps was a tremendously valuable capability.

With access to the UDID, we were able to use a common identifier for a device that would always be the same between through both the MDM channel as well as within our apps.

For instance, we used a device’s UDID as the primary identifier when storing Apple’s APNS magic token in our push provider’s database. When iOS 7 was released, the [UIDevice deviceIdentifier] method would return the vendorIdentifier value (which would always start with FFFFFFFFF), and that value would be registered in our push provider database. Of course when our MDM software wanted to send a push notification to the user via our app – using the UDID that MDM still has access to – there wasn’t a valid match found in the database any longer. So push no longer works in our app.

The fix is easy, but will just take some work:

In the app, change from deviceIdentifier to vendorIdentifier

Report the vendorIdentifier value to our MDM server

When iOS version ≥ 7.0, use the vendorIdentifier value instead of UDID when sending a device identifier to our push provider service

I’m sure this is just one of several “little things” we will be discovering as users upgrade to iOS 7, but such is the nature of tech!

I love the fact that Southwest is rolling out WiFi to their fleet. More and more flights I am on of theirs have WiFi and is great when I am in a pinch to get some work done.

However, as the rollout has been increasing, so has packet RTT (round trip time). I took a flight today from Boise to Las Vegas and had consistent RTT times of ~700ms. From a flight between PHX and SFO, I had >20% packet loss and RTT between 1000ms and 5000ms. Trace routes were blocked so I couldn’t see where the delay was taking place. This meant web applications were pretty much unusable and email even took a long time to sync (and actually failed more times than worked).

I wrote a note to Southwest to make them aware of the issue, and they wrote a very nice and well thought out response. They indicated that their engineers are aware of the issue and are working to resolve the problem. As usual with Southwest, I was very impressed with their through response and they even gave me free WiFi access to use within the next year.

That said, if you are reading this post wondering if you should pay those 8 hard-earned-dollars for WiFi, you just may want to hold off a few months while they work out those kinks. This has been an issue for me for over the last month or two, so progress appears to be slow.

Since the software is still under NDA, I can’t elaborate on any details, but I can share my experience. In short: I got it working, but man it sucked to get there.

For the 5th Developer Preview, with the release coming around the recently confirmed iPhone 5S/6 announcement on Sept 10, there are still a good number of bugs (many of which I reported like a good developer). Granted this is essentially a 1.0 release of a substantial piece of software so this is to be expected, but I hope some of these get ironed out soon so the coolness of their CI solution may be fully realized.

Again, sparing details, Apple has been doing a lot to simply and automate the provisioning profile and certificate management experience – both in Xcode 5 and on the CI server – but as a result there are a lot more things that can go wrong that the developer doesn’t have much visibility into. And as of now, a lot goes wrong with the new automated processes.

But this isn’t really a new issue: prior to this point, I have become accustomed to manually managing all provisioning profiles and developer/distribution certificates because the semi-automated systems never seemed to work right for me. However, now all of the UI for this manual management has been largely stripped in the new version. Don’t get me wrong, I think the new methodology will be great if they iron out the bugs as manual management of this stuff is not ideal for the developer community at large.

So, I bring this up because the CI server must compile and sign code, and therefore have all of the correct provisioning profiles and certificates must be downloaded and installed to do this. In the new OS X Server tool, acquiring these components is supposed to be very straightforward (the user experience is for sure in the right direction), however execution just isn’t there yet. I basically had to resort to performing the broken tasks myself via CLI, and only then could I get it working properly.

Once that got squared away, I did get to see how awesome and powerful Bots are going to be for developers that can benefit from CI. We are already planning automatic deployments to TestFlight, which ensures our testers will be able to use our latest and greatest builds to test without any manual deployment steps required by a developer.

I’m really excited that Apple decided to add CI as a feature to Xcode, I just hope the final release is substantially more stable than it is now.

For our Lync 2013 infrastructure at UWR, we are using bandwidth.com SIP trunks, an inGate SIParator, and a single Lync 2013 Front End.

We are using the Lync 2013 call conferencing feature, and when an inbound call is re-directed to the Lync 2013 infrastructure (via the SIParator), the call connects just fine. However, after the caller types in their conference ID and are about the be transferred into the conference, the call goes silent for a little, then a friendly message states “Sorry, I cannot connect you to the conference at this time”, then hangs up. Nice.

Looking at the SIP trace, the Lync 2013 is initiating a SIP reINVITE to point to some new media ports on the FrontEnd server, presumably because they correspond to the conference destination.

The reINVITE is forwarded out to bandwidth.com and the bandwidth.com returns a 200 OK, with all of the remaining SIP and SDP headers you’d expect. The SIParator forwards this to the Lync 2013 mediation server on the FE, and….. no ACK. From there bandwidth.com retries to send the 200 OK, and the SIParator tries to resend it to the Lync 2013 server as well, but eventually, the call is disconnected with a 481 Call Leg Doesn’t Exist.

For the sake of testing, I set up the following call flow for inbound conference bridge calls:

bandwidth.com > inGate SIParator

inGate SIParator -> ShoreTel PBX

ShoreTel PBX -> SIParator

SIParator -> Lync 2013 FE

To my surprise, everything worked perfectly. The trace followed this path as you’d expect, although the SIParator was smart enough to act as the b2bua and relay the audio directly between the Lync 2013 server and bandwidth.com (all with only taking up 1 session license). Clearly there is some difference between the way the reINVITE is handled between the ShoreTel PBX and Lync, vs. bandwidth.com and Lync…

So, for now I am using this “hairpin” topology to get things working. This is not ideal because I am consuming two ShoreTel SIP Trunk licenses per conference call, instead of the much better alternative of zero ShoreTel SIP Trunk licenses per call

My next step to resolve this is upgrade the SIParator to the latest build to see if that fixes the issue (running 4.9.2, latest is 4.10.2). If that doesn’t do it, I’m going to evaluate the diffs between the reINVITE dialog between the the Lync Server and ShoreTel vs. the Lync Server and bandwidth.com and see if there are any significant differences.

Hopefully this blog won’t end up like the vast majority of those on the internet (with this being the one and only post), but I am finally starting a basic blog to share my techy experiences with the world.

I’ve been meaning to do this for years as the tech community has graciously published information and knowledge on the internet that has helped me through a countless number of challenging problems, and has ultimately helped develop my skills to where they are today.

This blog is my effort to give back to the next guy that is stumped banging their head against the desk trying to understand WHY, and as a result hopefully make the world just that much better by helping out.

I will be posting blog entries about all sorts of things, from tech musings and analysis, to product management strategies, to code and configuration-level challenges that had me stumped.