読者です 読者をやめる 読者になる 読者になる

Gadget開発の基本

Mobile OpenSocial

前エントリを参照していただければ、多少Pythonがわかる方ならば自分で試してみることもできると思うので、基本的な概念と雰囲気を伝えるよう努力していきたいと思う。

まず、ContainerとGadgetという二つの要素が登場する。

  • Gadgetは、例えば、MacのDashboardであったり、iGoogleのGadgetのように、様々なアプリケーション作成者が提供するアプリケーションである。
  • Containerは、それらのGadgetの実行環境、Gadgetをホストするサイトである。例えば、Mac OS XApple自身やサードパーティが提供するDashboardアプリケーションの実行環境であり、iGoogleサードパーティのGadgetをホストするサイトである。

DashboardアプリやGadgetがHTML, JavaScript, CSSを使って構成されるのに対して、以下で述べる「モバイル版ガジェット」は、i-modeブラウザ1.0等のJavaScript未対応のクライアントを想定しているため、HTMLだけで構成されている。正確には、ガジェットが実行環境/ホストに対して要求するスペックと、ガジェットの実体/コンテンツのHTML断片を含んだXMLで構成されている。

前エントリで紹介したmobile-gadget-engineは「モバイル版ガジェット」をホストするために必要なライブラリで、examples/containerはその参照実装である。以下は、examles/containerの上で、自分のガジェットを作成するチュートリアルである。僕のなれているDjangoで書かせていただいたが、次エントリ以降で、Container/Gadget間での通信の内容やシーケンスについて解説していきたい(それによって「ガジェット開発」に必要なものが何かが分かる)と思うので、他の言語やフレームワークを使われている方には読み流していただきたい。



まず、普通にdjango-admin.pyを使って、Djangoアプリケーションを作成する。

$ django-admin.py startproject mygadget
$ cd mygadget
$ python manage.py startapp basic

mygadget/settings.pyにDEFAULT_CONTENT_TYPEを追加する。これはContainerが要求するContent-TypeがXMLのためである。

DEFAULT_CONTENT_TYPE = 'application/xml'

またmygadget/settings.pyのINSTALLED_APPSに今作ったmygadget.basicアプリケーションを追加しよう。

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'mygadget.basic', # Added!!
)

そして、Djangoの開発サーバーを立ち上げる。

$ python manage.py runserver 0.0.0.0:9088

mygadget/urls.pyを次のように書き換える。

# -*- coding: utf-8 -*-
from django.conf.urls.defaults import *

urlpatterns = patterns(
    'mygadget.basic.views',
    url('^basic/page1/$', 'page1', name='page1'),
    url('^basic/page2/$', 'page2', name='page2'),
)

蛇足かもしれないが、意味合いとしては、/basic/page1/というURLをmygadget.basic.views.page1という関数に対応付け、/basic/page2/というURLをmygadget.basic.views.page2という関数に対応付けるということ。

次にpage1, page2という関数を用意しよう。mygadget/basic/views.pyを編集して次のように書き換える。

from django.shortcuts import render_to_response

def page1(req):
    return render_to_response('basic/page1.xml')

def page2(req):
    return render_to_response('basic/page2.xml')

テンプレート内容をそのまま返すだけの、ごく単純なビューである*1。ここで使っているbasic/page{1,2}.xmlというテンプレートを準備する。

まずテンプレートを置くディレクトリを用意しなくてはいけないので、シェルに戻って、

$ pwd
/home/perezvon/mygadget
$ mkdir -p basic/templates/basic

で、mygadget/basic/templates/basicというディレクトリを作成する。page1.xml, page2.xmlを作るに先立って、その二つの親テンプレートとなるbase.xmlを作る。置く場所として、アプリケーションの拡張性という観点からいろいろな場所が考えられるが、ここではmygadget/basic/templates/base.xmlとした。テンプレートの構成の仕方は、Gadget開発のノウハウというよりも、Djangoアプリケーション開発のノウハウに属するので、ここでは詳しく述べることを割愛する。

mygadget/basic/templates/base.xmlの内容。

<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs title="{% block title %}mobile gadget{% endblock %}">
    <Require feature="opensocial-0.8" />
  </ModulePrefs>
  <Content type="html" view="profile"><![CDATA[
{% block profile %}{% endblock %}
]]></Content>
  <Content type="html" view="canvas"><![CDATA[
{% block canvas %}{% endblock %}
]]></Content>
</Module>

mygadget/basic/templates/basic/page1.xmlの内容。

{% extends "base.xml" %}
{% block title %}page 1{% endblock %}

{% block canvas %}
<h1>Page 1</h1>

<hr />

<a href="?url=/basic/page2/">To Page2</a>
{% endblock %}

mygadget/basic/templates/basic/page2.xmlの内容。

{% extends "base.xml" %}
{% block title %}page 2{% endblock %}

{% block canvas %}
<h1>Page 2</h1>

<hr />

<a href="?url=/basic/page1/">To Page1</a>
{% endblock %}

mobile-gadget-engine/example/containerを実行した状態で、まず、

http://localhost:8000/?url=/basic/page1/

にアクセスしてみよう。

page1
page1 posted by (C)perezvon

リンクをクリックすると、ページ2に遷移する。

page2
page2 posted by (C)perezvon

ここでポイントなのは、次の点である。

  • Contaierを介してGadgetを表示するには、GadgetのXMLのURLをパラメータurlで指定する必要がある。

という点である。

なお、GETリクエストではなく、POSTリクエストの時にも同様に、

<form method="post" action=".">
  <input type="hidden" name="url" value="/path/to/page/" />
  <input type="input" name="spam" value="" />
  <input type="submit" value="Submit" />
</form>

のようにurlパラメータをつける必要があるが、この点に関しては、次のエントリ以降でより実践的なガジェット・アプリケーションを作成するのでその時に解説する。


賢明な読者諸氏ならば、僕があえて"OpenSocial", "モバイル版OpenSocial"という単語を避けている、それゆえ何だかわからないエントリになっているということにお気づきだろうが、だって、これOpenSocialなの?「トラもトラネコもネコ科」という程度の親近性ではOpenSocialと言えるかもしれないけど、トラとネコくらいかけ離れていない?共通点、名前にトラってつくだけかよ、みたいな。

*1:この程度のものだったら自分でビュー関数を書かず、django.views.genericを使うのが普通だがここでは触れない