Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

如何创建Maemo应用程序

From 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 06:20.
149 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×