Tuesday, August 16, 2016

Towards your first iPhone app, in Python, with some working Phone functionality

Writing your first iPhone app, with Python

Mobile apps are awesome! Writing them is super-intimidating.


This post is going to outline how to go from not having anything relevant installed, and no accounts set up, assuming no particular knowledge beyond Python and general development. I’m expecting this will involve jumping through a few hoops. I expect you’ll need to be on OSX. I’m not going to try to streamline anything, or hide any details. That would be beneficial of course, but there is a first step of understanding the current state of affairs.


You’ll also see some sections written in italics. These hold notes from the future. As I start this, I don’t know what’s involved, and I want to preserve that. However, I want to come back from time to time to tell you things you’ll want to know.


ttime2_tn.jpg



Notes from the future: So, first up: I promise this works -- to a point. It shouldn’t take a whole lot more than say two hours to get an icon on your phone which pops up a launch screen and then exits. You’ll need some kind of OSX machine to run XCode on for the final push-button manouvre.



But first, a bit about me and why I’m doing this.

I’m a Python developer. I’ve never written an iPhone app, in any language. I’ve never written a mobile app. However, I’ve got a few things I’d really like to be able to do on my phone. It’s really non-obvious how to do integrations with the apps on my phone, because most of the things in the store are consumer-oriented and are not general-purpose. I suppose there are probably lots of things out there I don’t know about, but this post isn’t about that. I need a tool for experimentation and exploration, not an infinitely large backlog of product intercomparison work.

Back to our narrative

Okay, so where to start. I’m going to be using the “BeeWare” suite of tools and packages to do as much of this in Python as possible. As I understand it, this means I’ll be able to live in Python-land to a fairly high degree, and generally treat the xcode/iOS part of the procedure as a complex deployment manoeuvre.
The BeeWare collection of projects, applications, tools and libraries which can be used for all kinds of Python development. They provide a path forward to pushing Python onto iPhone in a way which is both (reasonably) Pythonic but also utilises the native functionality of the phone effectively.
We’ll be paying attention to the following BeeWare projects:


We’ll also be using the following non-BeeWare tools:
  1. Python 3.5: I recommend using Anaconda (https://www.continuum.io/downloads) to set up and manage your Python environments, and will be assumed in this post

Wait, is there a point here somewhere?

So far, you might be getting the impression that there are quite a few steps to this process, and that maybe none of them are that easy. That’s true. You might also be wondering, given all of that, whether the end product is really going to be worth all of that effort. Will Python-based apps be as good as a native Swift application? Will it be as responsive? Should I just bite a chunk off the apple and follow the crowd? That’s certainly how I feel.
As I write this, I don’t actually know. Thanks to the magic of post-editing, however, the following section contains my notes from the future, about what I was able to build, and whether the end product is satisfactory:

ttime2_tn.jpg
Notes from the future:  unfortunately this isn’t all quite demo-ready yet. It’s clearly not far off. The bugs aren’t in the fundamental iOS integration any more, they’re in the iOS bridge implementation of Toga, which is written in Python. https://sourcemaking.com/design_patterns/bridge describes what’s going on here. Each Toga back-end has a platform-specific class heirarchy which, while written in Python, contains logic specific to that platform.


This might look like bad news, but really it isn’t. Sure, we can’t go straight to the app development. However, we can now hook into the community of Python developers to implement the platform bridges for Toga. Given more time, it was entirely feasible for me to understand, debug and correct issues in the iOS Toga bridge.


Honestly, just seeing something launch on my phone was pretty exciting. It’s absolutely possible to execute Python code directly on the phone thanks to the Voodoo magic that Russell has been able to weave, and that’s mighty impressive. The next layer of the functionality onion is the GUI, and it’s just a matter of getting there.

Procedural Overview:

So, here is the end-to-end procedure, as I understand it. This simple twelve-point plan is all you need to become a mobile app coding ninja, right? Right? Don’t run these just yet -- we’ll step through them in the sections below -- but here you can see the overview all in one glance.
0. Create a project working directory for your files
                  (e.g. mkdir ~/iphone_app; cd ~/iphone_app)
1.     Set up a new virtual environment with Anaconda
2.     run ‘pip install cookiecutter’
3.     run ‘pip install briefcase’ You don’t need to do this actually
4.   run ‘pip install toga-ios==0.2.0.dev1’
5.     run cookiecutter https://github.com/pybee/Python-iOS-template --checkout 3.5
7.     Stick the uncompressed stuff into the directory that got made in step 4 (see online documentation item [1] below.
8.     Write the basic Python boilerplate that’s needed (described below)
9.     Somehow do something with Rubicon, because apparently it’s not part of the template or otherwise done for you Nope, this is a dependency and thanks to pip it Just Works
10.     Do a deployment magic with Briefcase This only applies to external things you want to port in, rather than things you’re building yourself here and now
11.  Load the directory of stuff into XCode
12.  Plug in ur phone and yaaay?
13. Build up the functionality you want in your application
Well, I think it’s a bit hard to get through the entire obstacle course in one go. I’m going to chunk this up into what I hope are separable work packages.


Chunking Out The Work

We’re not just looking to push out a demo here, we’re looking to establish a development loop of (write, test, deploy, test, fix): repeat. To do that we’re going to start with a Known Good Minimal implementation, push that onto the iPhone, then walk through building up a couple of iterations of our development lifecycle.


  1. Deploy some kind of zero-order application onto the iPhone with absolutely minimal functionality
  2. Get a super-simple GUI app working with Toga in my local development environment
  3. Get the GUI app working on the iPhone through that procedure
The logical step four would be automation and streamlining. However, as stated earlier, this post is constrained deliberately to covering how the existing tools work.

Overview of existing online documentation:



Step Chapter One: Zero Order iPhone App



Here is the code (called app.py)  that we’re going to use inside app.py for our first deployment:



import toga

print("Hello ChartyButtons")


As you can see, there’s not a lot of functionality here. However, it’s enough to result in an application that has an icon on your phone, and is runnable. We can use this to establish the end-to-end deployment process, and then use that to initialise our development loop.

Set up your Python environment:
  1. Download Anaconda
  2. Run ‘conda create -p ~/Development/envs/ios python=3
  3. Run ‘source activate ~/Development/envs/ios
  4. Run ‘pip install cookiecutter
  5. Run ‘pip install toga-ios==0.2.0.dev1


Set up your project directory (contains your files)


  1. Create a project working directory for your files                   
    (e.g. ‘mkdir ~/iphone_app; cd ~/iphone_app’)
  2. Stick the uncompressed stuff into the project working directory
  3. Run ‘cookiecutter https://github.com/pybee/Python-iOS-template --checkout 3.5’ ← Read the next bit before you actually run this!


Step four will prompt you for some information. This is also where you give your application a name, so you might want to think about something more exciting than FirstApp...


app_name [appname]:
formal_name [App Name]:
organization_name [Example Corporation]:
dir_name [iOS]:
bundle [com.example]:


Your app_name is like a variable name. It should be short and snappy. Lowercase, with no weird characters (emoji anyone?).


The formal_name is used as a label, but shorter is still better than longer. Weird characters are untested.


The organisation_name is intended to name the copyright owner.


The dir_name can be safely left at iOS, particularly if you’re going to be writing an app that genuinely targets multiple platforms. I used the name of my project again, and nothing bad happened.


The bundle doesn’t have a great name. It comprises reverse-ordered domain name, and is intended to provide a global namespace for your code so that no two applications can collide, and so that the organisational ownership of code is clear. You can probably type any parseable URL here. I actually have a domain name registered, so I used that. The default of com.example can probably be used for local development.

Set up your application


That last step of setting up your files using Cookie Cutter will create a nearly-but-not-quite-correct XCode project for you, with a stub location for your Python-based application functionality.


Screen Shot 2016-08-16 at 11.36.54 AM.png


I’ve called my app ChartyButtons. You can call yours whatever you like, of course. This image shows the layout you need. The default template expects you to create  __init__.py, app.py. The README incorrectly states these should go one level too high, in the AppName/app directory. These files actually need to be in AppName/app/AppName. You’ll also notice my screenshot has a ‘.git’ directory showing in it, which isn’t shown by default. It’s not relevant to this tutorial, but it’s what I use to keep track of progress and store versions of my code that I can go back to as needed.


The file “app.py” is the hook between iPhone-land and Python-land. This is where you will initiate your application logic. For now, just put this into app.py (no other lines required)


import toga

print("Hello ChartyButtons")


Deploy Your Application


You now have something that can be deployed onto your phone. You need to jump over into XCode, which is an application every OSX machine should have by default. You might as well go ahead and plug in your iPhone at this stage too.


Fortunately, this is the first time I’ve ever actually run XCode on purpose, so I should be able to capture all the things which a new developer might stub their toe on.


  1. Open your project directory in XCode
  2. Unlock your phone and push “play”
  3. OUTCOME! Your app is now on the phone!


The First Time Through:
There are a few things which seem to only happen the first time.


Push “play” and wait a couple of minutes for stuff to happen in the background. It looks like XCode needs to do some compiler black magic in the background. You’ll see something like this in a status bar at the top of your screen:


The status bar should now look like this:
Once this is all finished, you can push “Play” again to initiate the deploy to your phone.


At this point, you might see something about needing to set up your Apple ID in XCode:
Hit “Fix Issue”, and type in the credentials for your Apple ID. Then push “Play” again...

The first time round, you need to physically go into your phone’s settings, and accept your own developer certificate. XCode will show you the instructions for doing so, as pictured above.


Okay. so now when you push play, you should see an icon on your iPhone representing your app.


Step Chapter Two: Get a Super-Simple GUI app working locally using Toga

Okay, so you don’t really want to involve a physical iPhone in your fast-feedback development loop. The promise of Toga is that the application can be developed entirely in Python-land if you want to, and the iPhone compatibility is just a part of the last mile deployment.


So I will start by writing up a short tutorial on building a simple Toga app, but one which has some real functionality. My app is called ChartyButtons, and the purpose (for now) is going to be to display some important charts and graphics that I want to be able to reference easily.

ttime2_tn.jpg
Notes from the future: so, the first thing I did was write up a single-button application. The button did nothing, but it was there. Russell suggested I try getting that onto the iPhone. That’s when I discovered that the iOS Toga backend wasn’t a nicely mown lawn. I as got closer to it, I could see it was in fact tall grass, hiding spiders, snakes and the occasional piece of rusted earthmoving equipment. It obviously worked once, but that time is not now. So this section really doesn’t tell the whole story.


Here is the source code for a simple, single-button GUI app in Toga

import toga

def build(app):

   container = toga.Container()

   button = toga.Button(label='DataVsAlgo')
   container.add(button)

   return container

if __name__ == '__main__':
   app = toga.App(name='Charty Buttons', app_id='blue.neuron',   
                  startup=build)
   app.main_loop()


You can run this, and up pops a single button.


This is as far as I got during the time available.

Step Chapter Three: Get that App onto the Phone How to get into toga-iOS bridge development


ttime2_tn.jpg
Notes from the future: this work got a little crazy. There were dragons, line numbers, XCode debugging and branch merging. Russell got involved. We fixed stuff to make it less broken.


I have basically run out of time to write this chapter.


There’s a tool called “briefcase” which automatically packages up dependency packages into the XCode framework, but when things get hairy, you’re going to want to do this stuff the old fashioned way.

Getting your Toga app onto the iPhone properly is a little harder. The initial example didn’t make any calls to Toga, which meant that you never really needed any of its functionality.


  1. Set up a place in your development folder to store source code versions of the Toga stack
  2. Use symlinks to add them to your XCode project exactly according to the following screenshot




That is to say, you need to symlink from the app_packages directory directly to the package directory inside the containing directory for the source code. If everything were stable and “known good”, this is exactly what the briefcase BeeWare tool is intended to do for you. However, I recommend staying in charge for the time being.


This tutorial unexpectedly ends here. The future is now. For the next exciting installment, consider getting directly involved in the Great Mission! Thanks for reading this far!