×
Namespaces

Variants
Actions

如何创建Maemo应用程序

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata

文章
harrylister 在 21 Nov 2007 创建
最后由 hamishwillee 在 15 Dec 2011 编辑

Needs-update.png本文需要更新: 如果您发现这篇文章有用,请修复下面的问题,然后从文章中删除 {{ArticleNeedsUpdate}} 模板,以消除此警告。

原因: hamishwillee (21 Oct 2011)
I've just disabled or fixed 9 broken links. This indicates that the subject matter covered by the library is changing quickly, and this probably needs a thorough investigation to see if it is still valid.

本文是一篇对Maemo.org开源社区官方文档How to Write New Applications in maemo 4.0的非正式简体中文翻译版本。希望本文对广大中国开发者了解Maemo平台以及开发Maemo平台应用程序带来一些帮助:)


Contents

简介

  这是一篇为maemo平台创建新的应用程序的指南。

  当开始编写新的应用程序时,第一步首先是配置开发环境, Maemo Tutorial [1]介绍了这一步骤。该文档介绍实际的代码编写过程。

  作为范例,我们使用了只有少数重要特性的简易纯文本编辑。对这种纯文本编辑器来说最好的范例是gtk2edit和gpe-edit。从现在开始,此应用程序称为"MaemoPad"。

  MaemoPad有几个基本特性,比如"新建", "打开", "保存", "另存为...", "剪切", "复制", "粘贴", "字体", "全屏", "全屏"硬件设备按键处理, "发送-经电子邮件/蓝牙"和 "关闭"。 为了简易化,这里没有诸如"撤销", "重做",同一文中不同字体,图片等特性。

图1 MaemoPad 应用程序

  图1是MaemoPad的一个截图。如我们所见,MaemoPad应用程序在屏幕底端有它自己的工具栏,左上方角有下拉菜单。左边区域是用来显示文本的。

创建应用程序文件结构

  首先要创建MaemoPad的文件结构。这里显示的文件结构非常普遍而且它可被用在maemo SDK平台上各种应用程序。

  项目目录有四个子目录:

  •   src/: 包含源文件。
      在src/目录里,main.cMaemoPad代码的最高层。文件appdata.h包含应用程序所需的数据。下一节将介绍如何编写main.c代码和appdata.h。在src/ui/目录下的interface.c文件用来创建图形用户接口。callbacks.c里的代码用来处理MaemoPadmaemo平台间的消息。
  •   debian/: 包含和debian包相关的文件。
  •   data/: 包含应用程序运行时使用的数据文件;比如图标和帮助文件; 添加MaemoPad到菜单的.desktop文件, 一个DBUS .service文件。这里能找到更多关于.service文件的详情。
  •   po/: 包括本地化文件。
      本地化目录po/有一个POTFILES.in文件,列出了所需本地化文件的名称,另外翻译文件en_GB.po包含了应用程序使用的英国英语的本地化字符串,更多信息请查阅本地化一部分。

  除了上述4项子目录之外,项目的主目录仅包含3个脚本文件,使用GNU autoconf和<tt>automake工具来配置和编译该项目:

  •   autogen.sh 是使其它脚本文件生成项目的微脚本文件。
  •   configure.ac 包含如何为项目产生配置脚步的定义。
  •   Makefile.am 包含创建应用程序的<tt>src/, po/ ,data/目录及其内所有的Makefile所需的文件和子目录。

  编译项目常用的方法是

$ ./autogen.sh && ./configure && make;

  有关GNU autoconf和automake的内容该文档将不做介绍,更多内容请查阅参考文献[2]和[3]。 MaemoPad应用程序的文档结构应该是这样:

Makefile.am
autogen.sh
configure.ac
src/
Makefile.am
appdata.h
main.c
ui/
callbacks.h
callbacks.c
interface.h
interface.c
data/
Makefile.am
com.nokia.maemopad.service
maemopad.desktop
icons/
26x26/
maemopad.png
40x40/
maemopad.png
scalable/
maemopad.png
help/
en_GB/
MaemoPad.xml
po/
Makefile.in.in
POTFILES.in
en_GB.po
debian/
changelog
control
copyright
maemopad.install
maemopad.links
rules

应用程序代码主体

  在MaemoPadsrc/目录,有main.cappdata.h.

appdata.h

  appdata.h定义了AppData结构以获取应用程序数据。即使这些数据会因应用程序的不同而有差异,一个AppData结构样式应如下:

struct _AppData
{
AppUIData *ui; /* handle to app's UI */
HildonProgram *program; /* handle to application */
osso_context_t *osso; /* handle to osso*/
AppConfData *conf; /*handle to app's Gconf data */
};

  这里

  •   AppUIData一个包含所有UI对象指针的结构;如Hildon窗口,菜单项,工具栏; 和UI相关数据, 例如由一个布尔变量确定应用程序是否为全屏模式。
  •   HildonProgramMaemo教程中被介绍。它能够在AppUIData结构里被有选择地声明。
  •   osso_context_tMaemo教程介绍。
  •   AppConfData是应用程序里包含Gconf相关数据的结构。

  每个应用程序都将创建起自己的AppData变量,而且这些变量在函数里通常被当作参数传递,特别是在回调函数里,以使其能提取这些应用程序数据。

  许多应用程序将这些AppData变量声明为全局变量。

  MaemoPad's AppData结构如下:

struct _AppData
{
HildonProgram * program; /* handle to application */
HildonWindow * window; /* handle to app's window */
osso_context_t *osso; /* handle to osso */
};

  MaemoPadN.B. AppUIData指向AppData, 代替了AppData指向AppUIData。这并不是显著的差别,因为最终的目的是让函数能提取这些应用程序数据。

typedef struct _AppUIData AppUIData;
struct _AppUIData
{
/* Handle to app's data */
AppData *data;
 
/* Fullscreen mode is on (TRUE) or off (FALSE) */
gboolean fullscreen;
 
/* Items for menu */
GtkWidget *file_item;
GtkWidget *new_item;
GtkWidget *open_item;
GtkWidget *save_item;
GtkWidget *saveas_item;
GtkWidget *edit_item;
GtkWidget *cut_item;
GtkWidget *copy_item;
GtkWidget *paste_item;
/*....more truncated .....*/
}

main.c

  main.c通常实现以下功能:

  • 初始化GTK
  • 初始本地化资源
  • 创建Hildon应用程序范例
  • 调用函数,通常在interface.c被定义,创建主视图。
  • 连接主视图窗口和已创建的HildonProgram
  • 运行gtk_main()
  • 连接主视图的"delete_event"和回调函数,以处理适当的应用程序退出,比如销毁主视图窗口,释放已使用的内存及保存退出时的应用程序状态。
  • 调用gtk_main_quit()

  以下为带有注释的MaemoPad主函数:

int main( int argc, char* argv[] )
{
AppData* data;
HildonProgram* program;
MainView* main_view;
 
/* Initialize the locale stuff */
setlocale ( LC_ALL, "" );
bindtextdomain ( GETTEXT_PACKAGE, LOCALEDIR );
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
textdomain ( GETTEXT_PACKAGE );
 
/* Init the gtk - must be called before any hildon stuff */
gtk_init( &amp;argc, &amp;argv );
 
/* Create the hildon application and setup the title */
program = HILDON_PROGRAM ( hildon_program_get_instance () );
g_set_application_name ( _("MaemoPad") );
 
/* Create the data and views for our application */
data = create_data ();
data-&gt;program = program;
main_view = interface_main_view_new ( data );
hildon_program_add_window( data-&gt;program, data-&gt;window );
 
/* Begin the main app */
gtk_widget_show ( GTK_WIDGET ( program ) );
gtk_main();
 
/* Clean up */
interface_main_view_destroy ( main_view );
destroy_data ( data );
 
return 0;
}

用户界面接口

  图形用户接口被放在./src/ui/中,有两个.c文件: interface.ccallbacks.c

interface.c

  该文件将创建图形用户接口(GUI)并连接信号和事件到callbacks.c所定义的正确处理。查阅MaemoTutorial的GUI部分以了解更多如何在maemo里创建GUI的信息。如果熟悉GTK,那么建议从 GTK+参考手册 ([--hamishwillee : Disabled broken link https ://stage.maemo.org/svn/maemo/projects/haf/doc/api/gtk/index.html])[4]开始。

  常用的一种方式是在创建GUI时创建AppUIData结构变量。然后用不同的函数创建HildonWindow和小组件,比如create_menu(), create_toolbar().

  当创建每个组件时,AppUIData应该涉及同时创建的各种必需的UI对象。 下述摘录代码显示了AppUIData是如何创建的以及它是如何指向工具栏和工具栏上的“新建”按钮。

/* Creates and initializes a main_view */
AppUIData* interface_main_view_new( AppData *data )
{
/* Zero memory with g_new0 */
AppUIData* result = g_new0( AppUIData, 1 );
/*....*/
create_toolbar( result );
/*....*/
}
 
/* Create toolbar to mainview */
static void create_toolbar ( AppUIData *main )
{
/* Create new GTK toolbar */
main->toolbar = gtk_toolbar_new ();
/* Create the "New file" button in the toolbar */
main->new_tb = gtk_tool_button_new_from_stock(GTK_STOCK_NEW);
}

callbacks.c

  callbacks.c定义了处理所有可能由UI激发的信号和事件的函数。当在interface.c里创建不同的UI对象时,操作如下:

/* Create the menu items needed for the drop down menu */
static void create_menu( AppUIData *main )
{
main->new_item = gtk_menu_item_new_with_label ( _("New") );
/* Attach the callback functions to the activate signal */
g_signal_connect( G_OBJECT( main->new_item ), "activate",
G_CALLBACK ( callback_file_new), main );
}

  callback_file_new函数在callbacks.c被使用,当需要时可保存当前文件,并打开另一个需编辑的新文件。

void callback_file_new(GtkAction * action, gpointer data)
{
gint answer;
AppUIData *mainview = NULL;
mainview = ( AppUIData * ) data;
g_assert(mainview != NULL && mainview->data != NULL );
 
/* save changes note if file is edited */
if( mainview->file_edited ) {
answer = interface_save_changes_note( mainview );
if( answer == CONFRESP_YES ) {
if( mainview->file_name == NULL ) {
mainview->file_name = interface_file_chooser ( mainview, GTK_FILE_CHOOSER_ACTION_SAVE );
}
write_buffer_to_file ( mainview );
}
}
/* clear buffer, filename and free buffer text */
gtk_text_buffer_set_text ( GTK_TEXT_BUFFER (mainview->buffer), "", -1 );
mainview->file_name = NULL;
mainview->file_edited = FALSE;

  注意AppUIData结构变量mainview是如何被获取的,从而使用户可以有目的地高效操作。

  MaemoPad还有很多其他函数, 这些在Maemo教程里有介绍:

  •   文件保存/另存为/打开: 这些使用HildonFileChooserDialog
  •   编辑剪切/复制/粘贴: 这些使用Clipboard
  •   硬件按键: MaemoPad能够识别"全屏"按键(按F6)。它能把应用程序从全屏切换到正常模式,并可相反操作。许多其它的硬件按键事件都可被添加到MaemoPad。查阅Hardware keys
  •   字体/颜色选择: 这些在HildonFontSelectionDialogHildonColorChooser里有介绍。
  •   发送-经电子邮件/蓝牙: 参考Send Via functionality所介绍的的如何实现路径发送功能。

  更多有关GTK Widgets的内容可从 GTK+参考手册 ({{HamishW|Disabled broken link to https  ://stage.maemo.org/svn/maemo/projects/haf/doc/api/gtk/GtkWidget.html) 获取。

interface.h

  在接口头文件interface.h中, 共有函数为main.ccallbacks.c所定义. 在MaemoPad上, 保存修改提示的确认响应,Hildon错误提示的MaemopadError枚举类型和AppUIData都在此被定义。在一些其他的应用程序中. AppUIData也能在appdata.h里被定义。

  MaemoPadinterface.h如下:

#define MAIN_VIEW_NAME "AppUIData"
 
typedef enum {
MAEMOPAD_NO_ERROR = 0,
MAEMOPAD_ERROR_INVALID_URI,
MAEMOPAD_ERROR_SAVE_FAILED,
MAEMOPAD_ERROR_OPEN_FAILED
} MaemopadError;
 
/* Struct to include view's information */
typedef struct _AppUIData AppUIData;
struct _AppUIData
{
/* Handle to app's data */
AppData *data;
 
/* Fullscreen mode is on (TRUE) or off (FALSE) */
gboolean fullscreen;
 
/* Items for menu */
GtkWidget *file_item;
GtkWidget *new_item;
 
GtkWidget *font_item;
GtkWidget *fullscreen_item;
 
/* Toolbar */
GtkWidget* toolbar;
GtkWidget* iconw;
GtkToolItem* new_tb;
GtkToolItem* open_tb;
 
/* Textview related */
GtkWidget* scrolledwindow; /* textview is under this widget */
GtkWidget* textview; /* widget that shows the text */
GtkTextBuffer* buffer; /* buffer that contains the text */
GtkClipboard* clipboard; /* clipboard for copy/paste */
 
PangoFontDescription* font_desc; /* font used in textview */
 
gboolean file_edited; /* tells is our file on view edited */
gchar* file_name; /* directory/file under editing */
.........
};
 
/* Public functions: */
AppUIData* interface_main_view_new( AppData* data );
void interface_main_view_destroy( AppUIData* main );
char* interface_file_chooser( AppUIData* main, GtkFileChooserAction action );
PangoFontDescription* interface_font_chooser( AppUIData * main );
....

本地化

  本地化是指把应用程序翻译成不同的语言。在maemo里,简单的做法是把所有需要翻译的字符串放到一个.po文件,各个分配id, 然后在代码里使用这些id,而不是硬编码字符串。

  在maemo里用来处理翻译的字符串的函数是标准GNU gettext().

初始化

  当应用程序运行时,根据系统设置的本地语言,gettext()将把这些id翻译成正确的语言。应用程序应按以下方式初始化文本内容。

int main( int argc, char* argv[] )
{
........
/* Initialize the locale stuff */
setlocale ( LC_ALL, "" );
bindtextdomain ( GETTEXT_PACKAGE, LOCALEDIR );
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
textdomain ( GETTEXT_PACKAGE );
........
}

更多关于本地化的内容请查阅Maemo Localization How-to

文件结构

  本地化文件被保存在po/目录。MaemoPad的本地化将用到以下文件:

Makefile.am	
POTFILES.in
en_GB.po

  POTFILES.in包含了将被本地化的源代码文件列表。在MaemoPad里, 仅有main.cinterface.c包含需要本地化的字符串。

# MaemoPad 里需要被本地化的源文件列表
../src/main.c
../src/ui/interface.c

  en_GB.po文件包含了翻译成英国英语的文本.他包含如下几对 id/string:

msgid "maemopad_yes"
msgstr "Yes"

  在.po文件中,注释总是以"#"(井号)开头的。

使用en_GB.po

  使用en_GB.po msgid作为一个参数被传送到GNU gettext()函数以生成翻译字符串。在maemo里,推荐的方式是:

#define _(String) gettext(String)

因此,在MaemoPad里, 菜单->文件->打开 菜单的字符串按如下方式创建:

    main->open_item = gtk_menu_item_new_with_label ( _("Open") );

从源代码中创建.po文件

  有时候初始化并不是从开始就被执行时,从应用程序中本地化代码是很有必要的。通过从源文件中提取所有字符串到模板.po文件的方式,使用GNU xgettext创建.po files是有可能的。

xgettext -f POTFILES.in -C -a -o template.po"

  从man page索取更多有关xgettext的信息,简述如下:

  •   "-f POTFILES.in" 使用POTFILES.in以获取需要翻译的文件
  •   "-C" 是C-code类型的字符串
  •   "-a" 确保我们可以从指定的文件中获取所有的字符串
  •   "-o template.po" 定义了输出文件名

  接下来复制template.po./po/en_GB.po, 并添加或编辑所有英国英语的字符串。其他语言的处理同上述类似。

在菜单项中加入应用程序

  查阅Maemo教程有关如何操作此步骤地信息。简述之,就是将maemopad.desktopcom.nokia.maemopad.service文件保存在./data目录里,它们分别如下所示:

[Desktop Entry]
Encoding=UTF-8
Version=0.1
Type=Application
Name=MaemoPad
Exec=/usr/bin/maemopad
Icon=maemopad
X-Window-Icon=maemopad
X-Window-Icon-Dimmed=maemopad
X-Osso-Service=maemopad
X-Osso-Type=application/x-executable

(注释,行尾不能有任何空白字符)

# Service description file
[D-BUS Service]
Name=com.nokia.maemopad
Exec=/usr/bin/maemopad

连接maemo菜单

  当Debian包被装到maemo平台, .desktop.service文件就会把MaemoPad放置在Task Navigator里.更多信息查阅下面Debian打包部分。

添加帮助

  应用程序可以有其自己的帮助文件。帮助文件是被放在/usr/share/osso-help目录下的XML文件。比如英国英语的帮助文件/usr/share/osso-help/en_GB。在MaemoPad里,有一个data/help/en_GB/MaemoPad.xml目录下的文件,有很多简单的帮助内容。它规定了contextUID的中间部分和帮助文件名相同(不带后缀):

<?xml version="1.0" encoding="UTF-8"?>
<ossohelpsource>
<folder>
<h2>Help MaemoPad Example</h2>
 
<topic>
<topich2>Main Topic</topich2>
<context contextUID="Example_MaemoPad_Content" />
<para>This is a help file with example content.</para>
 
</topic>
</folder>
</ossohelpsource>

  通过使用ossohelp_show()函数(查阅osso-helplib.h), 帮助文件就能被显示在应用程序中。创建帮助菜单项之后,会连接一个回调函数:

void callback_help( GtkAction * action, gpointer data )
{
osso_return_t retval;
 
/* connect pointer to our MainView struct */
MainView *mainview = NULL;
mainview = ( MainView * ) data;
g_assert(mainview != NULL && mainview->data != NULL );
 
retval = ossohelp_show(
mainview->data->osso, /* osso_context */
HELP_TOPIC_ID, /* topic id */
OSSO_HELP_SHOW_DIALOG);
}

更多信息请查阅Help Framework HOWTO.

应用程序安装包

  Debian包是应用程序封装在一个文件里用来在基于Debian操作系统(如Maemo平台里完成简单安装的应用程序安装包。更多关于创建Debian包的信息可从Creating a Debian package中获取。此节我们的目的是创建可安装在Maemo平台上的MaemoPad程序的Debian包。

  如果要创建可使用应用程序管理器安装的安装包,请查阅Making Package for Application Manager.

创建debian/ Directory

  创建安装包需要一些文件。它们被放在debian/目录下。下列文件将被创建:

changelog
control
copyright
maemopad.install
maemopad.links
rules

  'rules' 文件定义了Debian包如何被生产。'rules'文件告诉我们文件应安装在什么地方。还有一个'control'文件用来定义即将被创建的包类型(通常是不同语言版本)。'maemopad.links'文件定义了到达 Task Navigator的链接。'maemopad.install'定义了MaemoPad里使用的本地化文件. Changelog 和 copyright files也是需要的,不然生成的安装包无法正常使用。'changelog'文件由安装包的版本数组成,简要记录了各个版本间的差别。'copyright'文件包含了安装包版权的纯文本信息。

  'rules'文件中最重要的几行是:

# Add here commands to install the package into 
debian/tmp/<installation directory>
 
$(MAKE) install DESTDIR=$(CURDIR)/debian/tmp/<installation directory>

  上述几行代码表明了安装包将在哪里安装。Debian/tmp是生成安装包的临时目录。

创建并生成安装包

  使用以下指令生成安装包:

"dpkg-buildpackage -rfakeroot -uc -us -sa -D"

  其结果应该是这些MaemoPad文件:

  maemopad_2.1.dsc

  maemopad_2.1 .tar.gz

  maemopad_2.1_i386.changes

  maemopad_2.1_i386.deb

  现在有一个.deb file.安装包可使用"fakeroot dpkg -i maemopad_2.1_i386.deb"指令进行安装。应用程序的图标此时应该在Maemo Task Navigator菜单, 同时它应该在那里显示出来。安装包可由"fakeroot dpkg -r maemopad"指令移除。

下载

  MaemoPad所有的源代码可从SVN下载。

参考文献

[1] Maemo 4.0 Tutorial

[2] http://www.gnu.org/software/autoconf//

[3] http://www.gnu.org/software/automake//

[4] GTK+ Reference Manual

[5] http://developer.gnome.org/gnome-vfs/

[6] http://www.debian.org/

[7] http://pangopdf.sourceforge.net/docs/index.html

FIN

Harrylister.jpg
Author: harrylister (harrylister_at_gmail_dot_com)

You can share this article under Attribution-Share Alike 3.0 Unported

This page was last modified on 15 December 2011, at 09:20.
243 page views in the last 30 days.
×