Upgrade to Pro — share decks privately, control downloads, hide ads and more …

A tale of two cellphones: Python on Android and iOS

A tale of two cellphones: Python on Android and iOS

Python is enjoying a surge in popularity due to it's features as a language. However, over the last 10 years, mobile platforms have increased in importance, and Python doesn't have a good story on these platforms.

In this talk, Dr Russell Keith-Magee will give a technical dive into the work the BeeWare project has been doing to make Python as simple to use on Mobile as it is on other platforms.

Video: https://www.youtube.com/watch?v=NqdpK9KjGgQ

B91373320dbc3bc52fcd870d3b21748f?s=128

Russell Keith-Magee

May 31, 2016
Tweet

Transcript

  1. A tale of two cellphones Python on Android and iOS

    Dr Russell Keith-Magee @freakboy3742 PyCon US 2016
  2. A tale of two cellphones Python on Android and iOS

    Dr Russell Keith-Magee @freakboy3742 PyCon US 2016
  3. None
  4. None
  5. What is "Mobile Python"?

  6. A native application delivered as a native application using native

    system APIs.
  7. A native application...

  8. ... delivered as a native application ...

  9. ... using native system APIs.

  10. What is currently possible?

  11. What is currently possible? You can: Write a native iOS

    application Write a native Android application Write a cross-platform application
  12. iOS

  13. CPython Issue 23670

  14. Using CPython on iOS

  15. Python-iOS-template Cookiecutter http://github.com/pybee/Python-iOS-template

  16. Accessing native libraries

  17. Swift

  18. Objective C NSURL *url = [NSURL URLWithString:@"http://pybee.org"];

  19. Objective C (intermediate) NSString *str = [ [NSString alloc] initWithCharacters:"http://pybee.org"

    length:16 ]; NSURL *url = [NSURL URLWithString:str];
  20. Objective C in C Class nsstring = objc_getClass("NSString"); SEL alloc

    = sel_registerName("alloc"); id str = objc_msgsend(nsstring, alloc); SEL init = sel_registerName( "initWithCharacters:length:"); str = objc_msgsend( str, init, "http://pybee.org", 16); Class nsurl = objc_getClass("NSURL"); SEL urlwithstring = sel_registerName( "URLWithString:"); id url = objc_msgsend( nsurl, urlwithstring, str);
  21. ctypes from ctypes import * libc = cdll.LoadLibrary("libc.so.6") libc.strchr.argtypes =

    [c_char_p, c_char] libc.strchr.restype = c_char_p >>> print(libc.strchr(b"abcdef", b"d")) 'def'
  22. ctypes and Objective C from ctypes import * lib =

    util.find_library(b'objc') objc = cdll.LoadLibrary(lib) objc.objc_getClass.argtypes = [c_char_p] objc.objc_getClass.restype = c_void_p NSString = objc.objc_getClass(b'NSString')
  23. Descriptors class ObjCInstance: def __getattr__(self, name): print("Getting attribute", name) def

    __setattr__(self, name, value): print("Set", name, "to", value) >>> obj = ObjCInstance() >>> obj.spam Getting attribute spam >>> obj.pork = "ham" Set attribute pork to ham
  24. Callables class Method: def __call__(self, *args) print("Invoke method with args",

    args) ... >>> method = Method() >>> method(1,2,3) Invoke method with args (1, 2, 3)
  25. Object creation class Method: def __new__(cls, *args) ...

  26. Rubicon

  27. Rubicon from ctypes import cdll, util from rubicon.objc import ObjCClass

    cdll.LoadLibrary(util.find_library('Foundation')) NSURL = ObjCClass('NSURL'); NSURL.URLWithString_("http://pybee.org/")
  28. Rubicon from rubicon.objc import * NSObject = ObjCClass(NSObject) class Handler(NSObject):

    @objc_method def initWithValue_(self, v: int): self.value = v return self @objc_method def pokeWithValue_(self, v: int) -> None: print ("Poking with", v)
  29. An iOS application in Python class PythonAppDelegate(UIResponder): @objc_method def application_didFinishLaunchingWithOptions_(

    self, application, launchOptions) -> bool: ... class MyViewController(UIViewController): @objc_method def loadView(self) -> None: self.title = 'Add item'
  30. Android

  31. CPython Issue 23496 https://bitbucket.org/xdegaye/pyona/src

  32. Jython

  33. Rethinking the problem

  34. Inside Python def sing(): for i in range(100, 0, -1):

    print("%d bottles of beer on the wall" %i) print()
  35. Python Bytecode import dis dis.dis(sing)

  36. Bytecode 2 0 SETUP_LOOP 47 (to 50) 3 LOAD_GLOBAL 0

    (range) 6 LOAD_CONST 1 (100) 9 LOAD_CONST 2 (0) 12 LOAD_CONST 5 (-1) 15 CALL_FUNCTION 3 (3 positional, 0 keyword pair) 18 GET_ITER >> 19 FOR_ITER 27 (to 49) 22 STORE_FAST 0 (i) 3 25 LOAD_GLOBAL 1 (print) 28 LOAD_CONST 4 ('%d bottles of beer on the wall') ...
  37. Java package com.example; public class Sing { public static void

    main(String [] args) { for (int i = 100; i < 0; i--) { System.out.println(i + " bottles of beer on the wall"); } } }
  38. Bytecode Max stack: 3 Max locals: 2 Bytecode: (39 bytes)

    0: BIPUSH 100 2: ISTORE_1 3: ILOAD_1 4: IFGE 34 7: GETSTATIC java/lang/System.out 10: NEW java/lang/StringBuilder 13: DUP 14: INVOKESPECIAL java/lang/StringBuilder.<init> 17: ILOAD_1 ...
  39. VOC

  40. An Android application in Python from android.widget import ListView class

    MainActivity( extends=android.app.Activity): def onCreate(self, state: android.os.Bundle ) -> void: super().onCreate(state) Log.i("MyApp", "Create new app") listview = ListView(self) ...
  41. Python-Android-template Cookiecutter http://github.com/pybee/Python-Android-template

  42. Cross platform

  43. Kivy

  44. Toga

  45. A Toga App import toga class TodoApp(toga.App): def startup(self): self.list

    = toga.List( data=[...], on_delete=self.remove_entry, on_refresh=self.refresh ) ...
  46. A Toga App (pt II) ... container = toga.NavigationView( title="Todo

    List", content=self.list, on_action=self.show_add_dialog ) self.main_window.content = container
  47. A Toga App (pt III) ... self.input = toga.TextInput(placeholder="thing to

    do...") self.add_item_dialog = toga.Dialog( title="Add item", content=toga.Container( self.input ), on_accept=self.add_entry ) ...
  48. A Toga App (pt IV) def show_add_dialog(self, widget): self.input.clear() self.show_dialog(self.add_item_dialog)

    def add_entry(self, widget): if self.input.value: self.list.add({'description': self.input.value}) def remove_entry(self, widget): ... def refresh(self, list_widget): ...
  49. bit.ly/toga-mobile-demo

  50. Packaging

  51. pip install briefcase python setup.py ios python setup.py android

  52. The future

  53. None
  54. The threat

  55. The opportunity

  56. It is the best of times, it is the worst

    of times, it is the age of wisdom, it is the age of foolishness, it is the epoch of belief, it is the epoch of incredulity...
  57. Thank you! russell@keith-magee.com @freakboy3742 pybee.org @PyBeeWare Python Mobile-SIG