Python

индекс
250,37

Пишем наше первое приложение на python for s60

imageВ прошлом топике, я постарался разогреть ваш аппетит, показав на что способен python for s60. Сейчас же я вам покажу, насколько легко писать приложения. Мы пройдем весь путь, начиная от выбора и установки необходимого софта, до упаковки программы в sis пакет.

Оговорюсь сразу: в этой статье мы будем разбирать пример, работающий на symbian 9.4 (смартфоны с тачскрином), хотя вы без особого труда сможете переделать пример и под более ранние версии symbian. Кроме этого, рассказ будет вестись с учетом работы на windows. Пользователи других операционных систем, без проблем смогут подобрать необходимый софт под свою OS.

Кстати, у программы, которые мы разработаем в этом топике, есть аккаунт в twitter :)

Начнем…

Инструментарий


Выбор инструментов основан на моем личном опыте. Возможно вы пойдете другой дорогой :)

Итак, нам понадобятся:
Установленный на ваш PC python, версии 2.5-2.6. Необходим он для работы утилиты ensymble (о которой будет сказано ниже), для тестирования набросков кода, да и куда уж программисту на питоне без него :)

Далее, скачиваем отсюда «пакет разработчика» для вашей OS. Для windows это будет PythonForS60_1.9.7_Setup.exe. Устанавливаем, и посмотрим что же у нас появилось.

Щелкаем по меню пуск, и находим Python for s60. Там у нас будет утилита ensymble, ссылка на on line документацию (off line доки можно скачать у меня отсюда), ярлык на папку PyS60 Dependencies, которая сейчас нам понадобится.

Открываем папку, и устанавливаем с нее в наш смарт python 1.9.7 (это python runtime, необходимый для работы программ, написанных на питоне, его же и нужно распространять вместе с вашей будущей программой), так же устанавливаем python script shell, который является оболочкой для запуска ваших скриптов непосредственно на смарте (кромер запуска, можно воспользоваться интерактивной консолью питона как со смарта, так и через bluetooth, через hyper terminal например).

Установили?! Теперь остается решить вопрос, в чем писать и как запускать написанное.

Для написания подойдет любой текстовый редактор с поддержкой utf-8, желательно с поддержкой подсветки кода. Какой из сотен редакторов выбрать, решать вам. Ничего особенного от него не требуется, запускать через него мы все равно не будем.

Запускать скрипты можно через эмулятор, но я пользуюсь другим способом, запуская на «живом железе».

У вас наверняка установлена Nokia PC Suite. В этом программе есть «диспетчер файлов», который встраивается в проводник. Но мне, человеку который ненавидим виндовый эксплорер, проще пользоваться замечательным плагином к TotalCommander, который называется NokiaFS (любителм других ФМ, думаю смогут найти в интернете подобные плагины).

Установите соединение между Nokia PC Suite и вашим телефоном. Удобнее всего пользоваться bluetooth, но подойдет и через кабель. Алгоритм прост: набираем код, нажимаем сохранить, переключаемся TC, копируем в телефон скрипт в папку data/python (на том диске, где у вас установлен python и script shell), далее в script shell нажимаем меню и «run script»… У меня руки, привыкшие к шорткатам и функциональным клавишам, делают это за 1-2 секунды :)

Для удобства, из data/python можно удалить примеры, давайте сделаем этот каталог нашей рабочей папкой.

Давайте что нибудь напишем


Напишем мы мега приложение, которое будет заставлять наш телефон мычать, при нажатии на кнопку в центре экрана. И чтобы наше приложение выгодно отличалось от подобных, добавим возможность подсчитывать, сколько раз наш телефон сказал «му» а так же возможность делиться нашими достижениями, добавляя сообщения в твиттер нашей программы twitter.com/pys60_cow :)

Я подразумеваю, что у вас есть хоть какие то знания языка программирования python. Если нет, бегом изучать :) Ссылку на документацию по специфичным для symbian модулям я привел выше.

Напишем «скилет» приложения. Так обычно начинаются мои приложения, в UI которого мы используем Canvas:
  1. #-*-coding:utf-8-*-
  2. import sys
  3. import e32
  4. from appuifw import *
  5. from graphics import *
  6. # app_path - путь, где у нас будут лежать картинки и звуки... app.full_name()[0] это первая буква
  7. # диска на с которого сейчас работаем
  8. app_path=app.full_name()[]+u':\\data\\python\\'
  9. # путь, где будет лежать файл с числом нажатий, позже этот путь мы изменим
  10. data_path=app_path
  11.  
  12. class Main:
  13.  
  14.  
  15.     def __init__(self):
  16.         # оключаем экранную клавиатуру
  17.         app.directional_pad=False
  18.         # открываем джепегешку с фоновой картинкой
  19.         self.splash=Image.open(app_path+'splash.jpg')
  20.         # инициализируем холст, на котором будем в дальнейшем работать
  21.         # в redraw_callback указываем функцию, которая будет вызывать при перерисовке экрана.
  22.         self.canvas=Canvas(redraw_callback=self.redraw)
  23.         # указываем, что виден на экране у нас будет canvas
  24.         app.body=self.canvas
  25.  
  26.     def redraw(self,rect):
  27.         # помещаем на canvas нашу картинку
  28.         self.canvas.blit(self.splash)
  29.  
  30. # создаем объект lock, который нужен, чтоб ваше приложение не закрылось сразу после открытия        
  31. lock=e32.Ao_lock()
  32. # при нажатии правую софт клавишу, освобождаем lock, приложение закроется.
  33. app.exit_key_handler=lock.signal
  34. a=Main()
  35. lock.wait()


Обязательно рисуем картинку к программе. Я не художник, для теста пока сгодится вот эта моя поделка.

image

Теперь осталось оживить наш нашу программу, добавив возможность нашей корове мычать. Открываем картинку в редакторе и линейкой меряем, где у нас находится картинка.
Добавляем в __init__ следующие строки:
# забиндим на координаты, где у нас иконка коровы функцию say_mu
self.canvas.bind(EButton1Down,self.say_mu,((44,171),(300,400)))
# открываем звук мычания коровы
self.mu=audio.Sound.open(app_path+'cow.mp3')

Теперь напишем функцию say_mu. Хочу обратить внимание, что функции сообщается, тьюпл, который содержит в себе координаты, куда мы ткнули пальцем, но они нам пока не нужны. И наконец пишем функцию, которая будет «мычать»
def say_mu(self,event):
    # если звук уже играет, останавливаем его
    if self.mu.state()==audio.EPlaying:
        self.mu.stop()
    self.mu.play()

Не забываем закинуть файл cow.mp3 и импортировать новые модули, которые нам сейчас понадобились.
import audio
from key_codes import * #для константы EButton1Down

Теперь добавим «счетчик му». Создаем файл mu.txt, записываем в него цифру 0, и перемещаем в наш рабочий каталог.
В __init__ добавляем строку:

self.mu_count=int(open(data_path+'mu.txt').read())

Путь к файлу mu.txt не случайно находится в переменной data_path a не в app_path, позже при сборке в sis я расскажу зачем так сделано. В функцию say_mu, дописываем строки:

self.mu_count+=1
open(data_path+'mu.txt','w').write(str(self.mu_count))

Нам ведь нужно увеличивать счетчик мычаний и сохранять в файл.
Осталось вывести надпись на canvas и перерисовывать его принудительно после каждого мычания. И итоге у нас получается такой скрипт:
  1. #-*-coding:utf-8-*-
  2. import sys
  3. import e32
  4. from appuifw import *
  5. from graphics import *
  6. import audio
  7. from key_codes import *
  8.  
  9. app_path=app.full_name()[]+u':\\data\\python\\'
  10. data_path=app_path
  11.  
  12. class Main:
  13.  
  14.     def __init__(self):
  15.         self.mu_count=int(open(data_path+'mu.txt').read())
  16.         app.directional_pad=False
  17.         self.splash=Image.open(app_path+'splash.jpg')
  18.         self.canvas=Canvas(redraw_callback=self.redraw)
  19.         app.body=self.canvas
  20.         self.canvas.bind(EButton1Down,self.say_mu,((44,171),(300,400)))
  21.         self.mu=audio.Sound.open(app_path+'cow.mp3')
  22.  
  23.     def redraw(self,rect=None):
  24.         self.canvas.blit(self.splash)
  25.         self.canvas.text((30,465),text=u'Промычало %s раз.'%(self.mu_count),fill=0xffffff)
  26.  
  27.     def say_mu(self,event):
  28.         if self.mu.state()==audio.EPlaying:
  29.             self.mu.stop()
  30.         self.mu.play()
  31.         self.mu_count+=1
  32.         open(data_path+'mu.txt','w').write(str(self.mu_count))
  33.         self.redraw()
  34.  
  35.  
  36. lock=e32.Ao_lock()
  37. app.exit_key_handler=lock.signal
  38. a=Main()
  39. lock.wait()


Осталась самая малость, постить по желанию пользователя в twitter :)
Для этого нам понадобится библиотека tweepy (можно воспользоваться и другой, но эта мне больше всего понравилась).

Добавить возможность работы со сторонним модулем достаточно легко. Можно распаковать пакет в какую нибудь папку и добавить этот путь в sys.path. Так же эти сторонние модули можно упаковать в zip архив и импортировать прямо оттуда, что собственно говоря мы сейчас и сделаем. Скачиваем мною подготовленный архив (у tweepy зависимость от simplejson), помещаем его в наш рабочий каталог и добавляем в скрипт строки:
sys.path.append(app_path+'my_modules.zip')
import tweepy

Реализация добавления твита займет всего пару строчек:
def post_to_twitter(self):
    name=query(u'Ваше имя:','text')
    if not name:name=u'Аноним'
    api = tweepy.API.new('basic''pys60_cow''pys60cow')
    api.update_status(u'У пользователся %s корова промычала %s раз!'%(name,self.mu_count))
    note(u'Твит добавлен!')


Не забудем создать меню, с одним единственным пунктом:

app.menu=[(u'Запостить твит',self.post_to_twitter)]

Теперь наш скрипт готов. И мы приступаем с следующей части нашей статьи.

Упаковка python скрипта в sis


Пора воспользоваться утилитой ensymble, которая идет в комплекте Python for s60. Запускаем это чудо утилиту.

image

Создаем где нибудь папочку для нашего проекта, например c:/temp/Pys60Cow, и помещаем туда файлы cow.py, cow.mp3, splash.jpg, my_modules.zip.
Переименовываем cow.py в default.py

Теперь поговорим о размещении файлов в установленной приложении.
Сам скрипт, с необходимыми ему файлами, такими как графика и пр. ляжет в папку x:/private/UID/, где x — диск, на который мы установим приложение, а UID — uid приложения. Эта папка доступна read only, поэтому данные приложения следует помещать в другую папку, например в x:/data/PyS60Cow/, поэтому мы и водили в нашу программу две переменные app_path и data_path. Теперь их нужно будет поменять на те, которые будут у нас использоваться в реальности.

В первую очередь сгенерируем валидный UID для программы. Для этого запускаем ensymble, выбираем script directory, жмем browse и выбираем папку c:/temp/Pys60Cow. Запускаем упаковку по кнопке Create и видим окно с множеством предупреждений:

image

И вот он наш сгенериованный UID. Окрываем default.py и редактируем app_path и data_path:

app_path=app.full_name()[0]+u':\\private\\eecc323a\\'
data_path=app.full_name()[0]+u':\\data\\Pys60Cow\\'

Соответственно в ensymble нажимаем more, и в списке настроек, в поле uid вписываем 0xeecc323a. Так же мы сразу задать версия приложения в формате X.YY.ZZ
Теперь разберемся с папкой data/PyS60Cow, которая должна установится на смартфон и содержать файл mu.txt. В c:/temp/PyS60Cow создаем любую папку, например other, в ней директории с той структурой, которая должны быть на смартфоне. В нашем случае это подпапки data/PyS60Cow туда то и копируем файл mu.txt. В ensymble в настройке Additional Options прописываем опцию --extrasdir=other

Теперь пришла пора иконки. Иконка приложения для sis приложения должны быть в svg формате. Можете взять мою готовую иконку к этому приложению. Далее добавляем в Additional Options опцию --icon=путь_к_иконке например --icon=c:\temp\icon.svg

Нажимаем заветную кнопочку Create, устанавливаем получившийся sis пакет в наш смартфон и пытаемся запустить и видим ошибку о нехватке модуля cgi. Не беда, просто ensymble «забыла» положить этот модуль в sis пакет. Добавим его вручную, дописав в additional options --extra-modules=cgi. Собираем еще раз. Все теперь наше приложение готово, и радует наши пытливые умы :)

Скачать готовый sis файл можно отсюда, а папочку, готовую к упаковке, содержащую в себе скрипт, медиа файлы и пр., возьмите здесь
+55
31 октября 2009, 20:59
100

комментарии (31)

–6
DileSoft #
отделите абзацы переводами строк, пожалуйста.
0
kAIST #
Так нормально?
–5
DileSoft #
Лучше, но здесь тоже надо:

–5
DileSoft #
Здесь:

Не забудем создать меню, с одним единственным пунктом:
app.menu=[(u'Запостить твит',self.post_to_twitter)]
Теперь наш скрипт готов. И мы приступаем с следующей части нашей статьи.

–6
DileSoft #
На:

Не забудем создать меню, с одним единственным пунктом:

app.menu=[(u'Запостить твит',self.post_to_twitter)]

Теперь наш скрипт готов. И мы приступаем с следующей части нашей статьи.
+1
kAIST #
Исправил, спасибо! Действительно, визуально стало выглядеть лучше.
–4
DileSoft #
Ага. И скриншоты тогда уж тоже отбейте. :)
+2
kAIST #
Пофиксил, еще раз спасибо!
+9
oe24 #
Вообще-то это все лучше обговорить и дать советы по хабрапочте, а не в пространстве комментов!
–1
Busla #
это орфографические ошибки можно трактовать однозначно, а вариантов оформления может быть множество — почему же не делать это открыто
0
oe24 #
Вот это да! Спасибо. Скоро, думаю, начну пробовать!
+3
oe24 #
Побольше бы таких статей на Хабре!
0
TWINc #
Статья супер, сразу захотелось купить Нокию и кодить :)
+2
kAIST #
Не обязательно нокия нужна…
Советую посмотреть этот список платформ, на которые портировали python, возможно вы пользуетесь, сами того не зная, девайсом, на котором можно программировать на питоне :)
+1
TWINc #
Ну это не совсем то… Одно дело портированный питон, а другое дело всякие гуевые либы, хорошая интеграция с ОС.
0
kAIST #
Ну на win mobile, например есть портированный Tkinter, wxPython, то есть с gui уже проблем нет.
На ipod, я думаю тоже найдутся либы
0
sparkle #
Вот наконец-то выдался удобный момент применить любимый язык для написания софта для любимого смарта (:
Скажите, а как на S60 с быстродействием? Сильна разница от написанных с помощью SDK от Nokia?
Надеюсь интерпретатор питона не тяжелый (сколько кушает оперативы и т.д.) под этой платформой?
0
kAIST #
Производительность конечно меньше чем если бы писалось на Си. Но для многих задач хватает.
Тем более, часто используются сишные обертки над нативным API, и получается, что в скорости мы практически не проигрываем. Посмотрите на мои приложения, описанные в предыдущем топике. Они работают быстрее, чем аналоги на Си :)
Что касается оперативной памяти, тут немного посложнее. Приложение, которое рассмотрено в этом топике, пожирает 5 mb ОЗУ.
+18
Nikon_NLG #
«давайте сделаем этот каталог нашей рабочей попкой. » — шикарно звучит :)
0
kAIST #
fixed… Долго не мог понять, что в этой фразе не так :)
0
AbnormalUnit #
Очень интересная статья.
Но есть несколько вопросов. При попытке установить рантайм на телефон (nokia N78) пишет вот такую вот ошибочку:
«невозможно установить. компонент встроен»
Не подскажите пути решения этой проблемы?
0
kAIST #
Вы точно устанавливаете python 1.9.7? В ранних версия ветки 1.9.х была такая проблема, связанная с тем, что python runtime устанавливает так же PIPS (P.I.P.S. Is POSIXon Symbian) библиотеки, и если они уже были установлены, вылезает такая ошибка… Давненько о ней мне не писали :)
Решение можно попробовать удалить следующее из диспетчера приложений:
-pips installer
-pips upgrate
-signal server
-pipes upgrate
а затем установить python runtime
0
AbnormalUnit #
Все оказалось более прозаично. Оно решилось сбросом настроек до заводских.
+1
kAIST #
Как говориться, «Семи бед — один хард ресет» :)
+1
kAIST #
Мда, твит аккаунт программы собрал за сегодня 9 фаловеров :)
+2
__aas__ #
self.mu=audio.Sound.open(app_path+'cow.mp3')
app_path=app.full_name()[]+u':\\data\\python\\'


os.path.join(), не?

А так весьма познавательно, спасибо!
НЛО прилетело и опубликовало эту надпись здесь
0
f0b0s #
нашли с чем сравнивать.
уж лучше сразу с машкодами, чего уж там.
0
sparkle #
Время загрузки приложения в примере — 8 секунд. Это довольно много, т.к. функционал минимален.
Я понимаю большую часть из этого времени происходить запуск интерпретатора. Так?
Можно ли это как-нибудь оптимизировать?
И еще эта пустая командная строка при запуске…
0
kAIST #
Нет в этом случае запуск долгий из за упакованных в zip дополнительных библиотек. То есть с таким же временем запуска можно сделать полноценный twitter клиаент, например :) Кроме этого время запуска можно уменьшить, не запаковывая доп библиотеки в zip, и закомпилировать их в pyc (pyo)
Время запуска интерпретатора замерить просто, создав проект с простым print 'hello world', или запустив python script shell.
С «командной строкой» немного сложнее. Дело в том, что пока мы не зададим app.body=Canvas, это строка будет перед глазами. Я обычно первым делом выводу на экран splash картинку, а потом делаю все остальное, например подгружаю ресурсы, импортирую большие библиотеки. Посмотрите на мои другие программы, там эту строку почти не видно.
0
MaEcTPo #
Подскажите, пожалуйста, а нет ли способа дебажить скрипты прямо на компьютере, в каком-нибудь эмуляторе. Ведь тот способ что вы описали не совсем удобен.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.