AWS GoT Hack: Lambda Function

To recap, I'm working on a 48-hour hack to help learn about AWS.  My goal is to:

Create a "Game of Thrones" Alexa Skill that allows the user to ask if a character is alive or dead, and responds with an accurate answer.

In the previous post, I created most of the very simplest implementation of our Alexa Skill.  Now we need to go write the code that backs up that skill. We'll be using AWS Lambda.

One creates a Lambda function from the Lambda Management Console. I'll skip the blueprint and configure the trigger to be the "Alexa Skills Kit".

Configuration

The configuration page is a bit more complex:

  1. I'll name the function "GoT-Skill"
  2. I'll use the Node.js runtime. 
  3. When I actually start coding, I'm going to upload a .ZIP file, rather than enter the code into a form field. However, just to get the function set up, I'm going to leave the template code here.
  4. I'll create a basic execution role.
    1. "Create a new IAM Role"
    2. Name it "LambdaBasicExecution"
    3. Hit "Allow"
    4. Launch IAM Management Console
    5. Select "LambdaBasicExecution"
    6. Hit "Attach Policy"
    7. Select "AWSLambdaBasicExecutionRole"
    8. Hit "Attach Policy" 
    9. Select "Choose an existing Role" and "LambdaBasicExecution". I had to wait a minute or so for the new role to appear.
  5. I'll leave the Advanced settings the way they are.
  6. Review the function and accept it.

OK, so now I have a very basic Lambda function that really does nothing.  But, at the top of this page I do have something I need: the ARN. I'll copy that, go back and paste it into my Alexa Skill.

Testing Alexa Skill

Now I can test my Alexa Skill. I'll enter an utterance ("where do you get your data") and see what happens.

The request JSON shows that the utterance is mapping correctly to the "Attribution" intent, but the response is:

The remote endpoint could not be called, or the response it returned was invalid.

Well, that actually makes sense as I haven't actually added any code to the template. I should go do that.

Lambda Code

Before I start writing code, I want to create a repo in which to store that code. I could do that using Github, but I'm trying to use a lot of AWS services, so I'm going to try AWS CodeCommit in the next blog post.

AWS GoT Hack: Alexa Skill

Read More

48-hour AWS Hack

Read More

Deploying your iOS app for testing

When you need to start testing your app on more than your personal device(s), you pretty much immediately run into the question: "How do I get my app on a device I don't have in my hands?". When you are a consultant, it is often the client who needs to do that deployment, and he or she is probably not an Xcode guru.  Here are my thoughts on how to accomplish this deployment with minimal pain.

TestFlight

So Apple bought TestFlight a while ago, and, while still a great tool, it has gotten a little harder to use.  There used to be no gating process when you submitted an app for distribution, but now Apple reviews the app before letting it be distributed.  It's not all bad, as, once you get past the first review, you don't need to submit new versions for review unless you have made "significant changes", which Apple describes as:" Significant changes means that you’ve added or removed a major feature or functionality."

Once your app has been approved for beta testing, TestFlight is a really great way to manage your beta users.  And the beta review process should help streamline the production review process when you release your app, so even that isn't all wasted time.

I highly recommend using TestFlight, but if you can't...

Ad Hoc Distribution

If you don't want to, or can't, use TestFlight, you can distribute your apps the "old way", which is called Ad Hoc distribution.  In this case you manually register the target devices (up to 100 per year) in Member Center.  You'll need to collect device IDs from your testers, add them to your account, and then re-build and archive so the device IDs are included in the archive.  The steps are as follows:

  1. Create an Ad Hoc provisioning profile.
  2. Register all test devices.
  3. Update the build string.
  4. Archive and export your app.
  5. Install the app on test devices.
  6. Solicit crash reports from testers.

Note that once you have finished steps 1 and 2, you don't have to do them again, unless you add or remove devices.

Create an Ad Hoc provisioning profile

To associate the test devices with your app, you need to create an Ad Hoc provisioning profile.  You can either do this manually in Member Center, or just let Xcode do it.

Register all test devices

This is really two steps:

  1. Gather device IDs from testers.
  2. Add the device IDs to Member Center.

It used to be easy to get your testers' device IDs: they simply downloaded and launched a third-party app, which detected their device ID and pre-populated it in a email.  Then they just addressed the email and hit send.  But then Apple hid the device ID from iOS apps, and the process got harder.

The easiest way for your users to get you the device ID is using Xcode, but how many of your testers have Xcode installed? The more likely, and only other way to get it is using iTunes, although, even there, not all users even connect their iOS devices to iTunes anymore.  I never do.

Update the build string 

Each version of your app needs a new build string, so iOS can differentiate it from previous versions. It is probably easiest, and certainly more interesting, to just use auto-incrementing build numbers.

Archive and export your app

When you are ready to distribute your app, you need to archive and optionally validate it, and then save it for Ad Hoc deployment.

Archiving is simply a different build type in Xcode. Note: save your archives, as you'll need them to symbolicate crash logs.

Exporting your app converts it into what we call an "IPA" (because it has the extension .ipa). This is the file your testers will install on their devices. Note: Xcode might bury the ipa inside a directory when saving.

Install the app on test devices

The "official", non-TestFlight way to install apps on testers' devices is to email them the app and have them use iTunes to install it.  But that is a pain.

I much prefer to use a third-party service, such as diawi.  With diawi, you simply upload your IPA and send a link to your testers. Clicking on that link will take your users to a web page from which they can easily install the app. And diawi can notify you when testers install the app.  And its free!

If you'd like diawi to send you an email with the link, and notify you when testers install your app, look under "More options...".  I WOULD PROBABLY CLEAR THE "ALLOW...' CHECKBOXES BELOW.

Solicit crash reports from testers

TestFlight automatically uploads crash reports from testers' devices.  If you don't use TestFlight, they'll have to do it manually.

Add / Remove Testers

You can add new devices using either method noted above.  Remove devices manually through Member Center.  SHOW HOW TO ADD DEVICE TO PROVISIONING PROFILE.  SHOW HOW TO GET NAME OF PROVISIONING PROFILE. HOW DOES PROVISIONING PROFILE GET CHOSEN WHEN IN AUTOMATIC MODE? DOWNLOAD AND DOUBLE-CLICK TO INSTALL PROFILE.

Hope these thoughts help you get your app into the hands of lots of testers.  Let me know what I've forgotten in the comments.

Wikipedia Time Machine (Part 2)

Part 1 introduced the concept of the Wikipedia Time Machine, a tool that will allow us to browse the Wikipedia as of a particular time and date, so as to avoid learning results of soccer games before we have a chance to watch them via DVR. I couldn't find any existing tools, so I started looking into writing it myself. I found a mechanism for specifying a page version in the URL, but I can't specify the version as a timestamp. So how do I translate a timestamp into a version? There must be a Wikipedia API, right? Back to Google!

And, indeed there is a Wikipedia API.  And one of the actions "query", allows you to get revision properties, and it looks like we can specify a timestamp and get the revision back.  This URL seems to do what we need:

http://en.wikipedia.org/w/api.php?action=query&titles=San_Francisco&prop=revisions&rvprop=timestamp|ids&rvlimit=1&rvstart=2014-06-21T20:00:00Z&format=jsonfm

It returns:

{
    "query-continue": {
        "revisions": {
            "rvcontinue": 613845875
        }
    },
    "query": {
        "normalized": [
            {
                "from": "San_Francisco",
                "to": "San Francisco"
            }
        ],
        "pages": {
            "49728": {
                "pageid": 49728,
                "ns": 0,
                "title": "San Francisco",
                "revisions": [
                    {
                        "revid": 613847076,
                        "parentid": 613845875,
                        "timestamp": "2014-06-21T19:59:58Z"
                    }
                ]
            }
        }
    }
}

Check out the "revisions" list. There's that revid we wanted.  So, using what we learned in Part 1, let's see if we can get the version we want.

I'll be damned. It worked! Take a look at the page. It even warns us at the top that we have an old revision, and it gives us the last changed date of the page. Nice.

Alright, so how do we build a tool to do this? That'll be Part 3.