Tizen-秘籍-全-

Tizen 秘籍(全)

原文:annas-archive.org/md5/59c244805fd4c2b3108345115096b5ab

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

Tizen 的故事始于 2011 年 2 月 11 日,当时诺基亚宣布与微软达成合作,导致 MeeGo 的终结。随即,英特尔和三星联手,启动了 Tizen 项目。Tizen 是 Linux 基金会的商标,截至今天,已有超过 40 家领先的公司直接参与该项目。

如今,移动市场被 Android 和 iOS 的双寡头所控制,二者占据了约 90%的所有移动设备市场份额。其余 10%的设备控制权主要由其他公司如微软和黑莓等分担。由于专利战、专有 API、封闭的应用商店和计费平台,创新的步伐正在放缓。作为一名工程师,我曾多次需要沟通,解释某些移动应用请求的功能无法实现,原因是操作系统的限制,或者仅仅因为缺少 API。

Tizen 来了,并且它大胆地尝试改变现状。它是一个创新的开源项目,为应用开发者、硬件供应商和电信运营商提供了新的机遇。在保证透明度并防止任何单一实体控制整个平台的情况下,Tizen 处于开源治理之下。其目标是建立一个可持续发展的社区,既包括公司,也包括个人,将其置于开发过程的中心,创造一个与 Android-iOS 双寡头竞争的替代方案。社区成员被鼓励贡献自己的力量,并明确知道从 Tizen 中可以期待什么。即便是较小的公司也可以参与平台的开发,他们的贡献可以与大公司贡献并列接受。每个贡献者都能参与定义 Tizen 的未来。运营商和 OEM 厂商的主要好处是,他们可以根据自己的需求和目标定制平台的软件和服务。

Tizen 面向不同的计算架构和形态:从智能手机、平板电脑、个人计算机、电视、数码相机,到家电和车辆等。世界及其技术在不断前进,互联网设备的数量正在快速增长。新的解决方案需要改善这些设备之间的通信,并使我们的生活更加便捷。Tizen 的出现弥补了这一空白,通过开源软件提供灵活性和标准化的解决方案。

本书的主要目的是支持您的开源之旅,并帮助您在开发用户友好和创新的移动应用程序及服务的过程中取得成功。

本书内容

第一部分 – 开始使用 Tizen

第一章,Tizen SDK,介绍了 Tizen 软件开发工具包及其工具,包括 Windows、Mac OS 和 Linux 的逐步安装指南,以及 SDB 用户指南。

第二章,Tizen 生态系统概述,概述了 Tizen 网页和本地应用程序的开发过程,并提供了通过 Tizen 商店发布和销售应用程序的指南。

第二部分 – 创建 Tizen 网页应用程序

第三章,构建用户界面,专注于图形用户界面。包括使用 jQuery Mobile 和其他 Tizen UI 组件构建应用程序的教程。本章还包含了在 HTML5 画布上绘制 2D 和 3D 对象的指南。

第四章,存储数据,包含关于在文件、局部存储和网页 SQL 数据库中存储数据的文章,以及一个关于通过互联网下载文件的教程。

第五章,创建多媒体应用程序,包含播放音频和视频文件、捕获图像、视频流、条形码生成和扫描的编程示例。

第六章,开发社交网络应用程序,包括开发最流行社交网络(Facebook、Twitter 和 LinkedIn)客户端网页应用程序的教程。

第七章,管理通讯录和日历,包括关于在日历中管理任务、事件和提醒的文章,以及管理通讯录中的联系人。

第八章,通信,专注于不同通信渠道的使用,如 SMS、蓝牙、NFC 和推送通知。

第九章,使用传感器,包含与硬件传感器(如 GPS、加速度计和陀螺仪传感器)相关的教程。本章的主要内容是基于位置的服务、地图和导航。

第三部分 – 移植与调试

第十章,将应用程序移植到 Tizen,包括将现有的网页、Android 或 Qt 应用程序移植到 Tizen 的选项和提示。还包括在 Tizen 上运行 Android 应用程序的兼容层教程以及将 Android 应用程序完整移植到 HTML5 的教程。本章还揭示了由社区驱动的 Qt for Tizen 移植,它允许将现有的 Qt 移动应用程序(如 Android、iOS、MeeGo、Symbian、SailfishOS 和 BlackBerry 10)部署到 Tizen 设备上。

第十一章,在 Tizen 中调试应用程序,包含了运行和测试 Tizen 网页应用程序的教程,以及 JavaScript 单元测试的相关内容。

第十二章,将 Tizen 移植到硬件设备,是一本入门指南,介绍如何构建基于 Tizen 的嵌入式控制系统。本章包括了构建 Tizen 平台映像以及在 ARM 和 x86 设备上启动它们的简要教程。本章中的信息对于开发新系统或将现有的嵌入式控制系统(如 IVI 或家庭自动化)移植到 Tizen 软件平台上非常有用。

本书所需的内容

需要具备 Web 开发中的一般编程基础知识。要跟随教程并尝试示例,您需要一台配置良好的开发计算机,操作系统可以是 Windows、Mac OS X 或 Ubuntu。

本书适合谁阅读

本书适合:

  • 移动应用程序开发人员

  • 对移动应用程序开发感兴趣的 Web 开发人员

  • 有兴趣将现有的 Web、Android 或 Qt 应用程序移植到 Tizen 的开发人员

  • 希望提升技能和知识的 Tizen 开发人员

本书的主要内容是 Tizen Web 应用程序开发,未包含关于基本 HTML5、JavaScript 或 CSS 编程的教程,因此需要对这些技术有一定的了解。本书同样适合没有 Tizen 或其他移动平台经验的开发人员,但他们需具备一定的 Web 技术基础。

本书的第三部分更为高级,可能会吸引开发嵌入式控制系统、车载信息娱乐系统(IVI)或家庭自动化系统和应用程序的人员。本部分内容也可能对质量保证(QA)工程师有用,因为它包含了手动和自动应用测试的指南。

约定

本书中包含了多种文本样式,用以区分不同类型的信息。以下是这些样式的一些示例,并附有它们的解释。

文本中的代码词、数据库表名、文件夹名称、文件名、文件扩展名、路径名、虚拟网址、用户输入和 Twitter 句柄如下所示:“我们的示例继承了 UiApp 并重载了几个方法,包括OnAppInitializing()OnAppInitialized()。”

一段代码如下所示:

<link rel="stylesheet" href="tizen-web-ui-fw/latest/themes/tizen-white/tizen-web-ui-fw-theme.css" name="tizen-theme"/>
<script src="img/jquery.js"></script>
<script src="img/tizen-web-ui-fw-libs.js"></script>
<script src="img/tizen-web-ui-fw.js" data-framework-theme="tizen-white"></script>
<script type="text/javascript" src="img/main.js"></script>

当我们希望你注意到代码块中的特定部分时,相关的行或项目会以粗体显示:

helloWorldFrame* phelloWorldFrame = new (std::nothrow) helloWorldFrame;
TryReturn(phelloWorldFrame != null, false, "The memory is insufficient.");
phelloWorldFrame->Construct();
phelloWorldFrame->SetName(L"helloWorldNative");
AddFrame(*phelloWorldFrame);

任何命令行输入或输出都按以下格式书写:

sdb devices

新术语重要词汇以粗体显示。您在屏幕上看到的单词,例如菜单或对话框中的内容,将以这样的方式出现在文本中:“启动 Tizen SDK 安装管理器并点击下一步。”

注释

警告或重要说明以如下框格式显示。

提示

提示和技巧如以下形式出现。

读者反馈

我们总是欢迎读者的反馈。请告诉我们您对本书的看法——您喜欢或不喜欢的部分。读者反馈对我们很重要,帮助我们开发出您真正受益的书籍。

要向我们发送一般反馈,请通过电子邮件发送至 <feedback@packtpub.com>,并在邮件主题中注明书名。

如果您在某个领域有专业知识,并且有兴趣撰写或为书籍贡献内容,请参阅我们在 www.packtpub.com/authors 上的作者指南。

客户支持

既然您已经成为一名 Packt 图书的骄傲拥有者,我们为您准备了一些内容,帮助您最大化地利用您的购买。

下载示例代码

您可以从您的账户下载所有已购买的 Packt 图书的示例代码文件,网址为 www.packtpub.com。如果您是从其他地方购买的本书,您可以访问 www.packtpub.com/support 并注册,以便将文件直接通过电子邮件发送给您。

勘误

尽管我们已尽最大努力确保内容的准确性,但错误仍然可能发生。如果您在我们的书籍中发现错误—例如文本或代码中的错误—我们将非常感激您能向我们报告。这样,您不仅能帮助我们改进后续版本,还能为其他读者节省困扰。如果您发现任何勘误,请访问 www.packtpub.com/support,选择您的书籍,点击 勘误 提交 表单 链接,并输入错误详情。一旦您的勘误被验证,您的提交将被接受,勘误信息将上传至我们的网站,或者添加到该书的现有勘误列表中,展示在该书的勘误部分。

盗版

互联网上的版权材料盗版问题在所有媒体中都是一个持续存在的问题。在 Packt,我们非常重视保护我们的版权和许可。如果您在互联网上发现任何形式的非法复制作品,请立即向我们提供该位置地址或网站名称,以便我们采取相应的措施。

如果您发现涉嫌盗版的材料,请通过 <copyright@packtpub.com> 联系我们,并附上涉嫌盗版内容的链接。

我们感谢您在保护我们的作者方面的帮助,以及您对我们为您提供有价值内容的支持。

问题解答

如果您在本书的任何部分遇到问题,您可以通过 <questions@packtpub.com> 联系我们,我们将尽力解决您的问题。

第一部分:开始使用 Tizen

Tizen SDK

Tizen 生态系统介绍

第一章:Tizen SDK

本章将覆盖以下食谱:

  • 安装 Tizen SDK

  • 在 Windows 上安装 Tizen SDK

  • 在 Mac OS 上安装 Tizen SDK

  • 在 Ubuntu 上安装 Tizen SDK

  • 管理扩展包

  • 自定义 Tizen IDE

  • 设置活动安全配置文件

  • Tizen Web 模拟器

  • Tizen 模拟器

  • 开始使用智能开发桥

  • 使用智能开发桥

介绍

本章介绍了开发 Tizen 应用所需的工具。详细描述了在三种支持的操作系统(GNU/Linux、Windows 和 Mac OS)上安装 SDK 的步骤。此外,本章还概述了开发环境、Web 模拟器、设备模拟器以及智能开发桥SDB)的用户手册。

对于那些急于开始编码的你们来说,可能会有些失望,因为本章没有包含任何代码片段。然而,请保持冷静,仔细探索所有食谱,它们将帮助你了解工具的工作原理。等你完成这些步骤后,你将能够更高效地开发 Tizen 应用程序。

安装 Tizen SDK

启动 Tizen 应用程序开发的第一步是下载并安装 Tizen SDK。所有支持的操作系统上安装过程相似。本食谱解释了 Tizen SDK 2.2.1 的基本安装过程。每个支持的操作系统的详细信息和注意事项将在本章节的后续食谱中讨论。

准备就绪

SDK 包含开发原生和 Web Tizen 应用所需的所有工具。它由基于 Eclipse 的 IDE、模拟器、Web 应用模拟器、工具链、几个示例应用程序和完整的文档组成。Tizen SDK 兼容以下平台:

  • Ubuntu(32 位和 64 位)

  • Windows 7(32 位和 64 位)

  • Mac OS X

开发系统的最低硬件要求如下:

  • 双核 2 GHz CPU

  • 至少 2 GB 的 RAM

  • 至少 6 GB 的空闲磁盘空间

注意

Tizen SDK 可以从 Tizen 项目官网免费下载,网址为developer.tizen.org/downloads/tizen-sdk

Tizen SDK 的硬件要求的更多细节可在developer.tizen.org/downloads/sdk/installing-sdk/prerequisites-tizen-sdk中找到。

尽管官方只支持 Ubuntu 这一 Linux 发行版,但一些用户已成功在其他发行版如 Fedora 和 Arch Linux 上使其工作。

提供了多个 Tizen SDK 安装选项。你可以选择网络安装、镜像安装或无 GUI 的命令行安装。

如何操作...

对于网络安装,请执行以下步骤:

  1. 首先,下载 Tizen SDK 安装管理器

  2. 启动下载的文件,然后在第一个屏幕上点击 下一步,如下面的截图所示:如何操作...

    Tizen SDK 安装管理器界面

  3. 在第二个屏幕上,接受条款和条件后再次点击 下一步

  4. 选择要安装的组件并点击 下一步。最后,指定 SDK 安装的目录并点击 安装 按钮。

    注意

    在安装过程中,可能会要求提供管理员权限。安装管理器将下载大约 1.5 GB 的文件。

如果你更倾向于离线安装,请按照以下步骤进行:

  1. 下载 SDK 安装管理器。

  2. 下载完成后,启动下载的文件。

  3. 选择 高级

  4. 进入 高级配置 窗口。点击对应的单选按钮选择 SDK 镜像

  5. 浏览到 SDK 镜像文件,点击 确定,然后点击 下一步

  6. 在下一个屏幕上,将显示条款和条件。接受后点击 下一步

  7. 选择要安装的组件并点击 下一步

  8. 最后,选择 SDK 存储的目录并点击 安装 按钮。

它是如何工作的…

Tizen IDE 基于 Eclipse。Eclipse 的大部分源代码是使用 Java 编程语言编写的。一般来说,使用 Java 创建的应用程序的主要优点是它们能够兼容不同的平台,这也是 Tizen IDE 和 SDK 能够在多个桌面操作系统上正常工作的主要原因。

另见

  • 关于在 Windows、Mac OS 和 Ubuntu 上安装的详细信息,请参考本章后续的教程。

在 Windows 上安装 Tizen SDK

尽管 Tizen 是基于 Linux 的操作系统,但可以在 Microsoft Windows 上开发 Tizen 应用程序。本教程将详细介绍在 Windows 上安装 SDK 的过程。

准备工作

建议在开始安装前,确保你的开发系统符合 Tizen SDK 的要求。Tizen SDK 兼容 32 位和 64 位的 Windows 7 版本,以及 32 位的 Windows XP 版本。尽管 Windows 8 未在官方支持的平台列表中,但 Windows 7 的版本应该与其兼容。

注意

请注意,即使已经安装了 32 位版本,64 位版本的 Windows 仍然需要 64 位的 JRE。

如何操作...

在 Windows 上安装 Tizen SDK 是直接的。完成安装的最简单方法是依赖于前面教程中描述的网络安装程序。

另见

  • 安装完成后,可以将 Tizen SDK 安装目录注册到 Windows 的环境路径中,这样就可以直接从任何位置运行 SDB。请参考与 SDB 相关的教程了解如何操作。

在 Mac OS 上安装 Tizen SDK

许多移动应用开发者使用 Mac OS 的原因之一是它是开发 iOS 应用所必需的。与 iOS 不同,Tizen 的开发工具没有这样的限制,可以在 Mac OS 以及其他流行的桌面操作系统上安装。

准备工作

Tizen SDK 的 Mac OS 网络安装管理器以标准磁盘镜像文件形式分发,扩展名为 dmg

如何操作...

下载 .dmg 文件,并按照提供的教程安装 Tizen SDK进行操作。

如果你计划在 Mac OS X 上开发原生 Tizen 应用,请根据你所使用的 Mac OS X 版本,按照 Apple 指南安装命令行工具 (developer.apple.com/library/ios/technotes/tn2339/_index.html)。

在 Mac OS X 10.7.5(也称为 Mac OS X Lion)或更高版本上,安装管理器可能因操作系统的安全设置而失败。必须修改这些设置,暂时防止 Mac OS X Gatekeeper 阻止安装管理器,从而继续 Tizen SDK 的安装。请执行以下步骤来配置 Mac OS X 上的 Gatekeeper,并解决该问题:

  1. 点击 Mac OS X 界面左上角的苹果菜单按钮。

  2. 选择系统偏好设置

  3. 点击安全性与隐私

  4. 选择常规标签。

  5. 要配置设置,请点击右下角的锁定图标,输入管理员用户密码,然后点击解锁

  6. 允许从任何地方下载应用设置为任何地方并确认更改。

  7. 再次启动Tizen 安装管理器并完成安装。

注意

安装成功后,安全设置可以恢复到之前的配置。或者,你也可以将安装程序作为单一应用从 Gatekeeper 中豁免。有关详细信息,请访问 Apple 的支持页面 support.apple.com/kb/HT5290

另见

  • 如果你有兴趣在成功安装 Tizen SDK 后将 SDB 添加到环境路径中,请参考与 SDB 相关的教程。

在 Ubuntu 上安装 Tizen SDK

Ubuntu 是唯一推荐并且完全支持的 Tizen SDK 的 Linux 发行版。在 Ubuntu 上启动 Tizen SDK 安装管理器之前,需要安装额外的软件。

本食谱包含四个主要步骤,用于安装所有必需的软件组件并成功完成 SDK 在 Ubuntu 上的安装。开始之前,请确保计算机上有至少 6 GB 的可用空间。

准备就绪

官方上,Tizen SDK 2.2.1 只与两个版本的 Ubuntu 兼容:12.04 和 12.10。尽管如此,完全可以在更新版本上安装并运行 SDK。这适用于以下版本的 Ubuntu:

  • 12.10 32 位

  • 13.04 32 位

  • 13.10 64 位

尽管 Ubuntu 13.10 没有官方支持,但 Tizen SDK 仍然可以成功安装。不过,运行 SDB 时需要应用与 libudev.so.1 相关的解决方法。有关如何修复 Ubuntu 13.10 上 SDB 的更多信息,请查看食谱中的故障排除部分。

如何操作...

完整的安装过程可以分为四个里程碑:

  1. 下载 Tizen SDK。

  2. 安装 Oracle Java Runtime Environment (JRE)。

  3. 安装依赖项。

  4. 安装 Tizen SDK。

访问 tizen.org 获取 Tizen SDK,或者执行以下命令,通过你的 Web 浏览器或命令行工具(如 wget)下载 Tizen SDK 2.2.1。例如,如果你使用的是 32 位版本的 Ubuntu,可以在终端运行以下命令:

wget https://cdn.download.tizen.org/sdk/InstallManager/tizen-sdk-2.2.1/tizen-sdk-ubuntu32-v2.2.71.bin

64 位版本的安装文件的 URL 稍有不同,可以通过执行以下命令进行下载:

wget https://cdn.download.tizen.org/sdk/InstallManager/tizen-sdk-2.2.1/tizen-sdk-ubuntu64-v2.2.71.bin

注意

这些 URL 可能会随时间变化。要下载 Tizen SDK 的另一个版本,请访问 developer.tizen.org/downloads/tizen-sdk 查看可用的链接。

在启动 Tizen SDK 之前,必须安装 Oracle JRE。请确保 OpenJDK 不被支持。如果你还没有安装 Oracle JRE,请按照以下步骤操作:

  1. 访问 Oracle 网站,根据你使用的 Ubuntu 版本,下载适用于 Linux 的 32 位或 64 位 JRE 7,并以 tar 压缩包格式提供,下载链接为 www.oracle.com/technetwork/java/javase/downloads/jre7-downloads-1880261.html

  2. 解压下载的 archive.tar -xzf jre-*.tar.gz 文件中的所有文件。

  3. 为 JRE 文件创建一个目录。然后,执行以下命令将提取的文件移动到该目录中:

    sudo mkdir -p /usr/lib/jvm/jre1.7.0sudo mv jre1.7.0_45/* /usr/lib/jvm/jre1.7.0/.
    
    

    注意

    JRE 文件和目录的名称可能会因你下载的版本而有所不同。

  4. 如果系统中没有 Java,请安装它。否则,建议使用以下命令进行更新:

    sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/jre1.7.0/bin/java 0
    
    

此外,Java 还可以在默认的 Ubuntu 网络浏览器 Mozilla Firefox 中启用。需要执行一些额外的步骤:

  1. 执行以下命令为当前用户创建一个目录,用来存储 Mozilla 插件:

    mkdir ~/.mozilla/plugins
    
    
  2. 创建指向上一步所创建目录的 Java 符号链接:

    ln -s /usr/lib/jvm/jre1.7.0/lib/i386/libnpjp2.so ~/.mozilla/plugins/
    
    

    提示

    创建插件的符号链接到/usr/lib/firefox/plugins/,或者对于 Ubuntu 13.10,创建符号链接到/usr/lib/firefox/browser/plugins/,以便为系统的所有用户启用它。启用 Java 后,必须重新启动 web 浏览器。

我们即将启动 Tizen SDK 安装程序,但在此之前,必须先安装一些依赖项。

确保安装以下软件包:

  • expect

  • gtk2-engines-pixbuf

  • libgnome2-0

  • qemu-user-static

  • gettext

  • module-init-tools

  • gksudo

  • libwebkitgtk-1.0-0

如果你不确定某个软件包是否已经在开发平台上安装,请执行命令 dpkg -s 后跟软件包名称或软件包列表进行检查。要安装前述列表中的任何软件包,请打开终端并执行 sudo apt-get install,后跟软件包名称,格式如下:

sudo apt-get install expect gtk2-engines-pixbuf libgnome2-0 qemu-user-static libwebkitgtk-1.0-0 gettext module-init-tools libudev-dev

Ubuntu 12.10 或更早版本的用户应通过执行以下命令安装 gksudo 软件包:

sudo apt-get install gksudo

请注意,如果你使用的是 Ubuntu 13.04 或更高版本,你将无法安装此软件包,因为它不再提供。相反,你应执行以下命令安装软件包 gksu

sudo apt-get install gksu

最后,继续安装 Tizen SDK。确保安装管理器的二进制文件具有可执行权限并启动它。请注意,<version><bits> 必须替换为与教程开始时下载的文件匹配的值:

chmod +x tizen-sdk-ubuntu<bits>-v<version>.bin
./tizen-sdk-ubuntu<bits>-v<version>.bin

启动安装管理器时,按照 安装 Tizen SDK 过程中的说明完成安装。

如果你不确定哪种安装类型适合你的需求,建议选择典型安装

还有更多…

在本节中,你将学习如何排查 Tizen 在 GNU/Linux 上的安装问题。

  • 无法启动 Tizen IDE,因为缺少或 JRE 版本不兼容(SDK 运行在 Eclipse 上,要求 JRE,需 JRE 6 或更新的版本)。

    如果遇到此问题,请在启动 Tizen SDK 安装程序之前,确保开发系统上已经安装了合适的 JRE 版本。

  • 无法运行安装程序,因为缺少软件包(缺少 "expect" "gtk2-engines-pixbuf" "libgnome2-0" "qemu-user-static" "libwebkitgtk-1.0-0" 软件包)。

    如果遇到此问题,请使用 shell 命令 apt-get 安装缺少的软件包。

  • 在 Ubuntu 机器上安装 Oracle Java 时出现问题。

    如果遇到此问题,请安装 java-package。然后,将下载的 Oracle JDK/JRE 压缩包转换为 .deb 文件。

  • 启动 Eclipse 时出现异常(线程 "main" org.eclipse.swt.SWTError: 没有更多句柄 [未知的 Mozilla 路径 (MOZILLA_FIVE_HOME 未设置)] 错误弹出)。

    如果遇到此问题,请使用 apt-get 安装 libwebkitgtk-1.0-0 包。

  • Tizen IDE 未显示 事件注入器

    如果遇到此问题,请确保已安装 Eclipse 的 Ajax 工具框架 插件。

  • 垂直滚动条显示不正常。

    要在最新版本的 Ubuntu 中禁用叠加滚动条,请执行以下命令:

    >gsettings set com.canonical.desktop.interface scrollbar-mode normal
    
    
  • SDB 在 Ubuntu 13.10 64 位上无法工作(sdb: 加载共享库时出错: libudev.so.0: 无法打开共享对象文件: 没有此文件或目录)。

    如果遇到此问题,请对 Ubuntu 13.10 64 位系统应用以下解决方法,自担风险,以便在 SDK 更新发布之前暂时解决该问题:

    sudo ln -s /lib/x86_64-linux-gnu/libudev.so.1.3.5 /lib/x86_64-linux-gnu/libudev.so.0
    
    

注意

请注意,libudev.so.1 对 Ubuntu 13.10 至关重要,如果不小心删除它或修改其文件权限,操作系统在重启后将无法正常启动!

另见

  • 如果你有兴趣将 SDB 注册为全局命令,请参阅 Smart Development Bridge 入门 相关的 SDB 文章。

  • 有关最新信息,请参阅 Tizen wiki 文章 在 Ubuntu 上安装 Tizen SDK,该文章自 2013 年 3 月 26 日起由本书的作者维护,地址为 wiki.tizen.org/wiki/Install_Tizen_SDK_on_Ubuntu

管理扩展包

Tizen 是一个开源软件平台,具有很高的灵活性。第三方开发者或公司可以为 Tizen SDK 开发扩展包。其他开发者可以通过使用特定仓库,在他们的应用程序中使用或滥用这些第三方包。一些 Tizen SDK 的扩展包可以在 developer.tizen.org/downloads/add-on-sdks 上找到。

如何操作...

请执行以下步骤以添加额外的仓库并安装附加的包:

  1. 启动 Tizen SDK 安装管理器。

  2. 点击 下一步 继续。

  3. 选择 额外仓库 打开对话框。

  4. 点击 添加

  5. 设置外部服务器以及仓库名称,然后点击 确定。仓库信息将在上一个窗口显示。再次点击 确定

  6. 选择所需的包并点击 安装

执行以下操作以删除额外的仓库及其安装的所有包:

  1. 启动 Tizen SDK 安装管理器。

  2. 选择 安装或更新 Tizen SDK 并点击 下一步

  3. 点击 额外仓库

  4. 选择要删除的仓库,然后点击 移除

它是如何工作的…

每个仓库包含一些额外的包,这些包是可选的,开发者可以随时添加或删除。仓库通过 URL 指定,因此必须连接到仓库服务器才能下载任何包。如果你在使用HTTP 安全协议HTTPS)连接仓库时遇到问题,可以尝试使用相同的 URL,通过 HTTP 进行连接。

如果你想从防火墙后的计算机访问仓库,必须使用代理。要配置代理,请启动安装管理器并点击代理设置按钮。

自定义 Tizen IDE

Tizen SDK 中包含的默认 IDE 基于 Eclipse。Eclipse 是一个开源软件,多年来它已成为移动平台应用开发的事实标准。具有 Android、Bada、Symbian 和 BlackBerry 10 开发经验的开发者已经熟悉 Eclipse,因为它或基于 Eclipse 的 IDE 被用于这些平台的应用开发。

注意

Android 开发者应注意,Tizen 提供的 Eclipse 与 Android 中的 Eclipse 使用方式有所不同。Android 开发工具ADT)是一个可以下载并安装的 Eclipse 插件。而与 ADT 不同,Tizen IDE 是通过 Tizen SDK 包提供的,目前没有单独的插件可用。

准备工作

Tizen 应用开发之旅的第一步是启动 Tizen IDE。它基于 Eclipse,因此 Tizen IDE 也会要求你选择一个工作区,这并不令人惊讶。如果你不希望每次启动 IDE 时都被要求选择工作区,只需勾选选项将此设置为默认并且不再询问。如果要在运行 Tizen IDE 时更改工作区,只需导航到文件 | 切换工作区

在 Tizen IDE 的第一次启动屏幕上会显示一个欢迎界面。点击工作台以打开 Tizen Web 视图并开始开发应用程序。如果你想查看文档,可以选择其他三个选项中的任何一个。你可以随时通过导航到帮助 | 欢迎返回到首页。如果你在寻找 Tizen 的官方开发文档,只需导航到帮助 | 帮助内容

如何操作…

对于很多开发者来说,IDE 的外观和体验是提高生产力的关键因素。Tizen IDE 支持 Eclipse 提供的所有自定义选项。本节仅包含一些关于背景和文本颜色自定义的提示。有关更多信息,请查看 Tizen IDE 和 Eclipse 文档,或深入研究偏好设置。

执行以下操作以更改文本编辑器的背景颜色:

  1. 导航到窗口 | 首选项,会弹出一个对话框。

  2. 导航到常规 | 编辑器 | 文本编辑器

  3. 外观颜色选项列表中调整背景颜色。

  4. 更改文本颜色。

文本颜色取决于编程语言的语法着色。Tizen Web 应用程序使用 HTML、CSS 和 JavaScript 开发,而本地移动应用程序的开发依赖于 C++。按照以下简单步骤更改语法着色:

  1. 导航至窗口 | 首选项,一个对话框将出现。

  2. 选择所需的编程语言并导航至编辑器 | 语法着色

  3. 调整颜色。

如果你想更改字体,请执行以下步骤:

  1. 导航至窗口 | 首选项,一个对话框将出现。

  2. 导航至常规 | 外观 | 颜色和字体

  3. 从列表中选择一种编程语言并点击编辑

还有更多...

这些是 Tizen IDE 中最流行和最重要的视图:

  • 项目资源管理器视图:该视图显示当前工作区中的所有资源。在项目资源管理器视图中,你可以管理项目、打开和编辑文件,以及执行构建、打包、签名和验证小部件或应用程序等操作。右键单击该视图内的内容,打开包含所有选项的上下文菜单。如果当前 Tizen IDE 视图中缺少项目资源管理器视图,你可以通过选择窗口 | 显示视图 | 其他... | 常规 | 项目资源管理器来添加它。

  • 属性视图:该视图显示所选资源的名称和基本属性。要查看资源的更多详细信息,请右键单击该资源并选择属性。要将其添加到当前 Tizen IDE 视图中,请导航至窗口 | 显示视图 | 其他... | 常规 | 属性

  • 日志视图:这是一个重要的工具,用于跟踪错误并调查在 Tizen 模拟器或连接到开发系统的设备上运行的应用程序的行为。应用程序运行时,日志消息会显示在日志视图中。支持以下消息类型:verbosedebuginfowarningerrorfatal。可以配置日志输出,以便仅过滤特定的消息类型,使用VDZIWEF软件按钮。按钮旁边是附加选项卡按钮,可以添加、编辑和删除更多过滤选项。还可以选择导出日志。如果日志视图不可见,通过启用以下选项来显示它,窗口 | 显示视图 | 日志

  • 控制台视图:该视图提供了多种控制台类型,这些控制台在 Tizen 应用程序的部署和调试过程中非常有用。如果控制台不可见,请导航至窗口 | 显示视图 | 控制台,将其添加到当前 Tizen IDE 视图中。要更改控制台的设置,请转到窗口 | 首选项 | 运行/调试 | 控制台

  • 连接资源管理器视图:该视图显示连接的设备和模拟器列表,并提供浏览其文件系统和传输文件的选项。选择列表中的一个项目,右键点击该项目以查看所有可用操作的菜单。要将连接资源管理器添加到当前的 Tizen IDE 视图中,导航到窗口 | 显示视图 | 其他... | Tizen

设置活动安全配置文件

必须创建并设置安全配置文件,才能成功在 Tizen 设备上部署和调试应用程序。根据我的个人观察,很多开发者在首次将应用程序部署到设备时,由于缺少安全配置文件而遇到问题。这个教程解释了几种生成证书并在 Tizen IDE 中设置的方法。

准备中

如果没有设置活动安全配置文件,当你尝试从 Tizen IDE 在设备或模拟器上运行应用程序时,屏幕上会显示以下错误信息:

准备中

因缺少活动安全配置文件而导致的签名问题

在从 Tizen IDE 启动任何应用程序之前,请先设置安全配置文件,以避免出现这个烦人的警告。

如何操作...

活动安全配置文件可以通过命令行手动创建,或通过 Tizen IDE 中集成的图形用户界面创建。

推荐的方式是通过 Tizen IDE 生成证书。步骤如下:

  1. 启动 Tizen IDE。

  2. 导航到窗口 | 首选项

  3. 导航到Tizen SDK | 安全配置文件

  4. 点击添加按钮。

  5. 输入配置文件的名称。

  6. 点击生成按钮填写作者信息。

  7. 点击确定以保存配置文件设置。

另一种方法是通过命令行创建证书并将其设置为 Tizen IDE 中的安全配置文件。如果你更喜欢使用终端,可以按照以下步骤操作:

  1. 启动终端并导航到目录<Tizen SDK 安装目录>/tools/certificate-generator/

  2. 如果你正在使用类似 Unix 的操作系统,如 Mac OS 或 Linux,执行 certificate-generator.sh。如果你使用的是 Windows,应该运行 certificate-generator.bat

  3. 系统会提示你输入证书信息。填写所有信息后,证书将被生成。

  4. 启动 Tizen IDE,因为生成的证书必须在其中设置。

  5. 导航到窗口 | 首选项

  6. 导航到Tizen SDK | 安全配置文件

  7. 点击添加按钮。

  8. 输入配置文件的名称。

  9. 输入证书文件的路径。

  10. 最后,点击确定按钮保存所有设置。

操作原理…

创建证书的过程无论你选择哪种方法或操作系统都是类似的。Windows 的批处理文件以及 Linux 和 Mac OS 的 bash 脚本都通过 java -jar 命令运行 CertificateGenerator.jar。此工具使用 Java 编写,文件格式为 Java 档案JAR)。使用 Java 进行这类应用程序的开发具有跨平台兼容性的优势,因为相同的代码可以在 Tizen SDK 支持的所有操作系统上运行:Linux、Mac OS 和 Windows。

Tizen Web Simulator

Tizen Web Simulator 是一个简化的工具,用于测试和调试网页应用程序。它包含在 Tizen SDK 中。Web Simulator 基于 Ripple-UI Framework,该框架最初由 BlackBerry(曾称为 research in motion)开发,用于测试 BB10 HTML5 WebWorks 应用程序,因此 Web Simulator 根据 Apache 软件许可证 v.2.0 发布。Web Simulator 提供以下功能:

  • 来宾修改提供了一个 JavaScript 后端,用于模拟 Tizen Web API

  • 配置面板用于触发与 Tizen 软件平台的地理位置、传感器、加速度和消息传递功能相关的事件和消息

  • 通过各种首选项自定义模拟器的行为

必须安装 Google Chrome 浏览器,因为它是 Tizen Web Simulator 的运行基础。这实际上意味着在 Google Chrome 上运行的 HTML5 应用程序也将在 Tizen 上运行。另一个好处是,Google Chrome 浏览器的所有开发功能都可以在模拟器中使用,包括可以通过按 F12 访问的远程检查工具。

准备工作

如果你打算在 Tizen Web Simulator 上测试应用程序,必须在开发系统上下载并安装 Google Chrome 浏览器。Google Chrome 浏览器的安装路径可以在模拟器的 Preferences 中指定。

如何操作...

有三种方式可以在 Web Simulator 中启动应用程序:

  1. 单击 Tizen IDE 工具栏上的 Run 按钮。

  2. 从 Tizen IDE 的菜单中导航到 Run | Run Configurations,并点击 Tizen Web Simulator Application

  3. Project Explorer View 中选择一个项目,并右键单击它。然后,导航到 Run As | Tizen Web Simulator Application

它是如何工作的...

Google Chrome 将自动启动 Web Simulator。通过编辑浏览器左侧面板中的配置来调整模拟器的方向和缩放。

请注意,Web Simulator 仅与 HTML5 网页应用程序兼容,对于原生应用程序无效。当启动网页应用程序时,模拟器会加载在 config.xml 中指定的 HTML 文件。默认情况下,该文件的名称为 index.html

另见

  • 请参考 第十一章,Tizen 应用调试 中的食谱,学习如何使用 Web 模拟器模拟事件并调试应用程序。

Tizen 模拟器

尽管强烈推荐直接在真实的 Tizen 设备上部署和调试应用程序,但开发应用程序并不强制要求拥有 Tizen 设备。Tizen SDK 随附了一个虚拟设备模拟器,开发人员可以创建与其测试需求匹配的自定义硬件规格的虚拟机。

设备模拟器是一个基于开源项目 Quick EmulatorQEMU)的虚拟机。它提供了完整的 Tizen 平台堆栈。模拟器管理器事件注入器 也是 SDK 中模拟器工具的一部分。与模拟器不同,模拟器严格执行设备规格,没有任何来宾修改。请注意,Tizen SDK 2.2.1 仅支持 x86 机器架构的来宾。

QEMU,Tizen 模拟器背后的引擎,是一个开源项目,用于可视化机器,允许你在开发机器的桌面上将另一个操作系统作为任务运行。Android 模拟器也基于 QEMU。有关 QEMU 和其许可证的更多信息,请访问 wiki.qemu.org/

Tizen 模拟器支持多种功能,最重要的功能如下:

  • 完整的系统仿真,包括 CPU、RAM 和外围设备(如摄像头)

  • 事件注入器用于事件模拟

  • 硬件加速的 3D 渲染支持的动画和 OpenGL ES

  • 电话功能

当然,模拟器与真实的 Tizen 设备相比有一些限制。这些差异影响功能的行为:

  • 输入系统:模拟器提供虚拟触摸屏,其驱动程序与物理设备的驱动程序不同。

  • 虚拟传感器:通过事件注入器接收与加速度、光线、陀螺仪、接近、运动、位置和电池相关的值。

  • 电话功能:语音电话、呼叫等待、外呼限制和消息功能通过事件注入器支持。视频通话、呼叫转移、来电限制、模拟器间通话和短信功能不受支持。

  • 电源管理:模拟器提供内部实现来开启和关闭显示屏。

  • 支持的媒体格式和编码:模拟器不支持 H.264 编码和 AAC+、增强 AAC+ 以及 FLAC 解码。

准备就绪

请确保你在屏幕分辨率至少为 1280 x 1024 像素并且图形驱动程序支持 OpenGL 的计算机上运行 Tizen 模拟器。推荐使用支持虚拟化技术VTx)的 Intel CPU。模拟器的性能取决于计算机的硬件,在资源较低的计算机上可能会运行缓慢。关于 Tizen 模拟器的要求,请参见developer.tizen.org/downloads/sdk/installing-sdk/prerequisites-tizen-sdk

如何操作...

要创建新的 Tizen 模拟器实例,请启动模拟器管理器并点击标有创建新虚拟机按钮。

选择模拟器的名称、显示分辨率、密度、皮肤和 RAM 大小。然后,启用或禁用 GPU 和 CPU 的硬件虚拟化。当所有配置设置完毕后,点击确认,如下图所示:

如何操作...

Tizen 模拟器

模拟器将在模拟器管理器的窗口中出现。点击播放按钮启动模拟器。Tizen 在虚拟机上的加载时间可能会根据开发系统的硬件不同而有所变化。请等待 Tizen 完全加载后再使用。

作为替代方法,高级用户可以通过终端使用以下语法的命令启动模拟器:

/emulator-x86 --skin-args <skin options> --qemu-args <QEMU options>

可以将分辨率的高度和宽度等皮肤选项以及各种 QEMU 选项作为命令的参数进行指定。有关支持的选项的详细信息,请查看官方 Tizen SDK 2.2.1 开发文档中的用户手册:

developer.tizen.org/dev-guide/2.2.1/org.tizen.gettingstarted/html/dev_env/emulator_startup_options.htm

另见

  • 你可以通过智能开发桥(Smart Development Bridge,SDB)与正在运行的 Tizen 模拟器进行通信。有关更多信息和详细内容,请查看下一个配方。关于在模拟器上部署和运行应用程序的描述以及使用事件注入器(Event Injector)模拟事件的示例,请参见第十一章,在 Tizen 中调试应用程序

开始使用智能开发桥

智能开发桥(SDB)是一个用于与 Tizen 模拟器或连接的 Tizen 设备进行通信的命令行工具。它在 Tizen 中的作用与Android 调试桥ADB)在 Android 中的作用相同。SDB 是 Tizen SDK 的一个重要组成部分,并随 SDK 一起安装。SDB 管理多个设备连接,并提供应用开发和调试的基本命令。SDB 的主要功能如下:

  • 管理与设备和/或模拟器的连接

  • 开发系统与连接的 Tizen 模拟器/设备之间的文件传输

  • 远程 Shell 用于在 Tizen 仿真器/设备上执行命令

  • 从主机到 Tizen 仿真器/设备的端口转发

  • 调试应用程序

SDB 作为典型的客户端-服务器应用程序工作,由三个主要组件组成:

  • 一个在开发系统上运行的客户端,可以通过命令行使用 SDB 命令来调用。

  • 一个管理与 Tizen 仿真器和设备连接及通信的服务器,它作为后台进程在开发系统上运行。

  • 一个在每个 Tizen 仿真器或设备上运行的守护进程。

尽管不是强制性的,但将 SDB 添加到环境路径中是很方便的。为了做到这一点,请根据开发机器的操作系统,按照此文档中的步骤操作。

注意

SDB 也作为标准包提供给 Linux 发行版。如果您有兴趣仅安装 SDB,请从 download.tizen.org/tools/ 下载适合您 Linux 发行版的相应包。

准备工作

在成功安装 Tizen SDK 后,SDB 位于 tizen_sdk/SDK/sdb 目录下。要使用客户端,必须在该目录下执行 SDB 命令,除非 sdb 的位置已被添加到环境路径变量中。

如何操作...

要将 SDB 添加到 Windows 7 的环境路径中,请执行以下步骤:

  1. 右键点击桌面上的 计算机 图标。

  2. 选择 高级系统 设置。

  3. 系统属性高级 选项卡中点击 环境变量 按钮。

  4. 小心地将 SDB 的位置添加到 Path 变量中。

如果您使用的是 Windows XP,以下步骤将帮助您将 SDB 添加到环境路径中:

  1. 右键点击桌面上的 计算机 图标。

  2. 点击 属性

  3. 选择 系统属性高级 选项卡。

  4. 点击 环境变量 按钮。

  5. 小心地将 SDB 的位置添加到 Path 变量中。

    注意

    在 Windows 上,修改的设置只有在重新启动后才会生效。

要将 SDB 添加到所有用户的环境路径中,请在 Ubuntu 中将 SDB 目录添加到 /etc/environment 文件中定义的路径。注销并重新登录,或者直接重启以应用更改。

要将 SDB 添加到所有用户的环境路径中,在 Mac OS X Leopard 及以上版本上,请在 /etc/paths.d/ 目录下创建一个文本文件,并使用 root 权限设置 SDB 的位置,例如,sudo -s 'echo "<tizen_sdk>/sdb" > /etc/paths.d/sdb'

在类 UNIX 操作系统(如 Linux 和 Mac OS)上,可以通过一个快捷且简单的替代方法,使用 root 权限在 bin 目录中创建指向 SDB 的符号链接,从而实现类似效果,而无需修改 /etc/environment 或在 /etc/paths.d 创建文件。例如,可以使用 sudo ln –s <tizen_sdk>/sdb /bin/sdb

请注意,两个示例中的 <tizen_sdk> 必须替换为实际的路径,具体取决于安装位置。

另见

  • 请查看下一个教程,了解如何使用 SDB 的完整功能。

使用智能开发桥(Smart Development Bridge)

SDB 是一款功能强大的工具,具有众多功能和特性。尽管您可以在不理解 SDB 的情况下使用 Tizen IDE 成功开发应用程序,但建议您探索该工具的各种选项。SDB 是开发者管理连接设备、传输文件和调试应用程序时最好的伙伴。

如何操作...

执行以下步骤以启用并使用 SDB:

  1. 请确保设备上的日期和时间是正确的。

  2. 通过导航至 设置 | 开发者选项 | USB 调试,启用 Tizen 设备的开发者模式和 USB 调试。

  3. 将 Tizen 设备连接到计算机。

  4. 在控制台中使用以下语法运行 SDB 命令:

    sdb [option] <command> [parameters]
    

根据 Tizen 2.2.1 官方开发指南,前述命令中的 option 参数可以是:

  • -d: 选择设备。此选项将指定的命令发送到连接的 USB 设备。请注意,如果有多个 Tizen 设备通过 USB 连接,此选项将失败。

  • -e: 此选项用于控制模拟器。错误处理方式与 -d 选项类似。如果运行多个模拟器,则该命令会失败并返回错误。请将命令指向唯一运行的模拟器,如果存在多个模拟器,则会返回错误。

  • -s <serial number>: 连接到开发者计算机的 Tizen 设备或模拟器通过其序列号进行标识。-s 选项后应跟设备的序列号,SDB 将确保仅将命令发送到指定设备。

以下是所有支持的 SDB 命令列表,并附带一些简要信息:

命令 详细信息
devices 提供已连接设备的列表。
connect <host>[:<port>] 通过 TCP/IP 连接设备。
disconnect <host>[:<port>] 断开设备连接。主机和端口参数是可选的。如果未指定,它将断开所有设备。
push <local> <remote> [-with-utf8] 将文件从开发系统传输到连接的 Tizen 设备。
pull <remote> [<local>] 将文件从连接的 Tizen 设备传输到开发系统。
shell 访问连接的 Tizen 设备或模拟器的远程 shell。
shell <command> 在连接的 Tizen 设备或模拟器上远程执行单个 shell 命令。允许执行以下命令:lsrmmvcdmkdircptouchechotargrepcatchmodrpmfindunamenetstatkillall
dlog [option] [<filter-spec>] 打印连接的设备或模拟器中的当前日志。
install <path_to_tpk> 安装 tpk 包。
uninstall <appid> 使用应用的 ID 卸载应用。
forward <local> <remote> 配置端口转发的 localremote 套接字。
help 显示 SDB 帮助信息和使用指南。
version 打印 SDB 版本号。
start-server 如果 SDB 服务器未运行,启动 SDB 服务器。
kill-server 如果 SDB 服务器正在运行,终止该服务器。
get-state 显示与设备连接的状态。
get-serialno 显示连接的 Tizen 设备的序列号。
status-window 显示连接设备的状态,直到开发者手动终止命令。
root <on&#124;off> 启用或禁用 root 账户模式。

注意

如果同时运行并连接多个 Tizen 模拟器和/或设备,必须在 SDB 命令中指定目标设备,否则命令执行将失败。

Android 开发者会发现 Tizen Smart Development Bridge 和 Android Debug Bridge 之间有很多相似之处。这两个工具名称相似并非偶然。两个工具有共同的目的,大多数命令在两个平台上使用相同的关键字执行,并且行为相似。

以下是 SDB 命令的几个使用场景:

  • 列出已连接的设备:

    >sdb devices
    
    
  • 运行特定设备的 shell:

    >sdb emulator-2610 shell
    
    
  • 在 Tizen 设备上运行单个 shell 命令:

    >sdb emulator-2610 ls
    
    

另见

第二章:Tizen 生态系统介绍

在本章中,我们将介绍:

  • Tizen 应用生命周期

  • Tizen Web 应用编程

  • Tizen Web API

  • 本地化 Tizen Web 应用

  • 打包 Tizen Web 应用

  • Tizen 本地应用编程

  • 打包 Tizen 本地应用

  • 成为 Tizen Store 卖家

  • 发布应用到 Tizen Store

介绍

生态系统和社区对于每个开源项目至关重要,Tizen 也不例外。Tizen 是万物操作系统。它面向不同的设备、形态和 CPU 架构,因此它是一个灵活的软件平台,可以用于多种用途。

Tizen 可以在 ARM 或 i586 兼容处理器的设备上运行。第一款商用 Tizen 设备是三星的 NX300 相机。2014 年,三星还推出了几款搭载 Tizen 的智能手表,英特尔制造了迷你电脑 NUC。如果你对在各种硬件设备上启动 Tizen 或甚至构建自己的设备感兴趣,请查阅本书的最后一章。

Tizen 支持三种可安装的应用类型:

  • 网页应用使用 HTML5、JavaScript 和 CSS 开发。这是推荐的类型,因为这些应用支持所有 Tizen 配置文件(如 IVI、移动、可穿戴等)。

  • 本地应用是使用 C++ 和 Tizen 本地 API 开发的。它们速度较快,但更复杂,且难以移植。

  • 混合应用结合了网页应用和本地应用。一个混合应用包含一个具有用户界面的单一网页应用和一个或多个相互通信的本地服务应用。

本章包含有关 Tizen 应用生命周期的信息,开发工具和技术的概述,以及通过 Tizen Store 发布和销售应用的指南。这是一本出色的入门指南,帮助你发布你的第一个 Tizen 应用。

Tizen 应用生命周期

Tizen SDK 提供了将好点子转化为优秀应用并发布到 Tizen Store 的工具。Tizen 应用的生命周期类似于 Android 和 iOS 移动应用的生命周期,包括以下部分描述的步骤。

准备工作

Tizen 应用的生命周期可以分为六个主要步骤,如下图所示:

准备工作

Tizen 应用生命周期

应用开发是一个持续的过程。你必须定期提供新的功能和改进的更新。要有耐心。有些步骤可能比预期的花费更多时间。有时,你可能还需要返回到之前的步骤,例如,如果 Tizen Store 的质量审核拒绝了应用。

在开始之前,请确保已经成功安装了 Tizen 开发环境。调试应用程序需要一个 Tizen 设备或模拟器。如果没有设备,可以使用 Tizen 模拟器管理器创建一个模拟器。

如何做到这一点...

  1. 想出一个好点子。

    每个伟大移动应用背后都有一个好点子。你只需要灵感,但不幸的是,据我所知,并没有严格的规则、标准或算法,所以你必须跳出框框思考。

  2. 设计应用的用户界面(UI)并实现后端。

    用户界面和用户体验是将一个好点子转化为一个拥有大量下载量的卓越应用程序的关键因素。仔细规划应用程序的开发路线图,并选择最佳的实现方式。如果你的应用程序与 Web 服务进行通信,合理地分配移动应用程序和服务器之间的负载,以实现最佳性能。UML 图可能有助于你在开始编码之前做好充分准备。始终记住,一个好的计划可以在开发过程中为你节省大量时间。

  3. 构建 Tizen 应用程序。

    Tizen IDE 提供了构建 Tizen 应用程序所需的工具,只需单击一下即可轻松构建应用程序。在开始构建之前,你需要配置其设置。导航到 Project | Build Configuration 以管理可用的构建设置。之后,你可以随时通过点击 F10 或导航到 Project | Build Project 来构建应用程序。

  4. 调试 Tizen 应用程序。

    在 Tizen 设备和模拟器上试用应用程序,验证其是否按预期工作。测试非常重要,因为即使是一个小的错误也可能会激怒用户,导致他们停止使用你的应用程序。

  5. 打包应用程序。

    应用程序的所有文件必须打包成一个可以安装在 Tizen 设备上的包。原生应用程序的包文件扩展名是 .tpk,Web 应用程序的扩展名是 .wgt

  6. 认证应用并将其发布到 Tizen Store。

    最终步骤是将你的应用发布到市场。通过应用商店(例如官方 Tizen Store)分发应用程序是接触全球数百万用户的最简便方式。

Tizen 是开放的,它的生态系统也是开放的。Tizen Store 是由三星维护的官方商店,但你也可以将应用发布到其他商店。如果你愿意,你甚至可以创建自己的商店。

另见

  • 关于 Tizen Web 应用程序的教程和示例可以在本书的第二部分找到。查阅 第十一章,在 Tizen 中调试应用,了解有关 Tizen 应用调试的详细信息。关于打包、认证和发布到 Tizen Store 的更多信息可以在本章的其他食谱中找到。

Tizen Web 应用编程

自 Tizen 初始发布以来,Web 应用程序开发一直是 Tizen 项目的一部分。这是平台上推荐的应用开发方法。数百万开发者已经熟悉了 Web 开发的基础知识,因此他们可以轻松地开始为 Tizen 开发应用程序。

Tizen SDK 提供了开发 Tizen Web 和混合应用程序所需的所有工具。Web 应用程序包含 HTML、CSS 和 JavaScript 文件,这些文件与扩展名 .wgt 的包一起打包。混合应用程序将 Web 应用程序与一个或多个原生服务应用程序结合起来。

准备就绪

Web 应用程序作为独立应用程序在 Tizen 上安装和执行,得益于Web 运行时WRT)引擎。所有标准的 HTML5 API 都得到支持。有些功能不被这些 API 覆盖,因此 Tizen Web 运行时通过提供额外的 JavaScript 函数来填补空白。

本食谱通过创建一个简单的 Hello World Web 应用并在 Tizen 设备或模拟器上运行它,演示了 WRT 的实际应用。

如何操作...

  1. 启动 Tizen IDE,并在提示时选择一个工作区。

  2. 进入文件 | 新建 | Tizen Web 项目

  3. 将会出现一个向导,用于创建 Tizen Web 应用程序项目。在模板中选择Tizen Web UI 框架单页面应用。输入项目名称,例如 hello。准备好后,点击完成

  4. 项目资源管理器中导航到 config.xml,并使用小部件配置编辑器打开它。默认情况下,双击应该会在小部件配置编辑器中打开该文件。如果没有,请将鼠标悬停在文件上,右键点击,选择用以下方式打开选项。

  5. 打开概览标签,将名称更改为 HelloWorld。这样,应用程序的名称将与项目的名称不同。

  6. 项目资源管理器中,打开 index.html,将其内容替换为以下源代码,并保存更改:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8"/>
        <meta name="description" content="Hello World!"/>
        <meta name="viewport" content="width=device-width,user-scalable=no"/>
        <title>Hello World!</title>
        <link rel="stylesheet" href="tizen-web-ui-fw/latest/themes/tizen-white/tizen-web-ui-fw-theme.css" name="tizen-theme"/>
        <script src="img/jquery.js"></script>
        <script src="img/tizen-web-ui-fw-libs.js"></script>
        <script src="img/tizen-web-ui-fw.js"
            data-framework-theme="tizen-white"></script>
        <script type="text/javascript" src="img/main.js"></script>
        <link rel="stylesheet" type="text/css" href="./css/style.css"/>
    </head>
    <body>
        <div data-role="page">
            <div data-role="header" data-position="fixed">
                <h1>Tizen Cookbook</h1>
            </div>
    
            <div data-role="content">
              <p>Hello World!</p>
            </div>
            <div data-role="footer" data-position="fixed">
                <h4>Packt Publishing</h4>
            </div>
        </div>
    </body>
    </html>
    

    提示

    下载示例代码

    你可以从你在 www.packtpub.com 账户下载你购买的所有 Packt 书籍的示例代码文件。如果你在其他地方购买了本书,可以访问 www.packtpub.com/support 注册并直接将文件通过电子邮件发送给你。

  7. 保存所有文件。

  8. 确保已经连接启用了开发者模式的 Tizen 设备,或者模拟器正在运行。如果不确定如何启用开发者模式,可以查看上一章的食谱 使用智能开发桥

  9. 项目视图中选择应用程序的项目,右键单击它,并在出现的菜单中选择以 Tizen Web 应用程序运行。作为替代方法,你也可以直接点击运行按钮来部署并启动应用程序。

如何工作…

创建新项目时,Tizen IDE 会自动生成目录结构,并在选择模板时创建文件。

应用程序的所有配置和权限都在 XML 文件 config.xml 中设置。Tizen IDE 提供了简化该文件编辑过程的方法。文件中存储的配置包括名称、标识符、版本、图标文件以及默认的入口文件 index.html。如果应用程序使用了敏感 API,还需要在此文件中描述权限来设置对敏感 API 的访问。

使用以下 HTML 代码包含了若干 JavaScript 和 CSS,以确保应用程序与 Tizen WRT 兼容,并使用标准的 Tizen 风格:

<link rel="stylesheet" href="tizen-web-ui-fw/latest/themes/tizen-white/tizen-web-ui-fw-theme.css" name="tizen-theme"/>
<script src="img/jquery.js"></script>
<script src="img/tizen-web-ui-fw-libs.js"></script>
<script src="img/tizen-web-ui-fw.js" data-framework-theme="tizen-white"></script>
<script type="text/javascript" src="img/main.js"></script>

文件 js/main.js 将由 IDE 生成,并且它将包含初始化应用程序和处理后退硬件按钮的 JavaScript 源代码。请注意,jQuery 也被包括在内,因为 Tizen Web UI 框架基于 jQuery Mobile。

如果你在从头创建 Hello World 应用程序时遇到任何问题,请使用书中提供的示例。

另请参见

  • 更多有关 Tizen Web 应用程序的示例和高级教程,请参阅本书第二部分的章节。

Tizen Web API

Tizen 提供了一系列符合 W3C/HTML5 规范的 API,并且与非盈利行业联盟 Khronos 一起创建开放标准。此外,还提供了一组额外的 API,用于访问设备的特定硬件和软件功能。这些 API 基于 JavaScript,必须使用此编程语言才能充分利用这些 API。

注意

本食谱仅简要概述了 Tizen API。有关更多信息和详细内容,请查看 SDK 帮助中提供的文档,网址为 developer.tizen.org/dev-guide/2.2.1/org.tizen.web.appprogramming/html/api_reference/api_reference.htm

准备就绪

Tizen 平台提供以下基于 JavaScript 的 API,用于开发 Web 应用程序:

  • 闹钟:该 API 通过提供的方法添加或删除日期和时间事件

  • 应用程序:此 API 管理已安装和正在运行的应用程序

  • 数据控制:该 API 帮助访问和控制其他应用程序的可用共享数据

  • :该 API 帮助安装和卸载包,或者检索已安装包的详细信息

  • 蓝牙:该 API 提供对短距离通信协议蓝牙的控制

  • 消息:该 API 提供通过不同流行通信渠道的消息传递功能:SMS、MMS 和电子邮件

  • 网络承载选择:该 API 控制和选择网络承载

  • NFC:此 API 提供与其他近距离设备的连接,使用 NFC

  • 推送:该 API 帮助接收和处理来自 izen 远程服务器的推送通知

  • 安全元件:该 API 访问安全智能卡芯片上的数据

  • 内容:该 API 发现和探索多媒体内容,如视频或音乐

  • 下载:该 API 提供通过 HTTP/HTTPS 下载文件的方法

  • 文件系统:该 API 提供访问文件系统、创建、读取和写入文件的方法

  • 消息端口:该 API 提供不同应用程序之间的通信功能

  • 书签:该 API 访问和管理书签

  • 日历:这个 API 用于访问和管理日历

  • 通话记录:这个 API 提供有关进出电话的信息

  • 联系人:这个 API 用于管理通讯录

  • 数据同步:这个 API 提供设备数据同步的接口

  • 电源:这个 API 用于电源管理

  • 系统信息:这个 API 提供有关电池、CPU、存储、WiFi、蜂窝网络等的信息

  • 系统设置:这个 API 提供对平台各类设置的访问

  • 时间:这个 API 用于获取日期和时间信息

  • Web 设置:这个 API 控制的是 Tizen Web 应用程序的 Web 视图相关设置

  • 通知:这个 API 用于通知用户与应用程序相关的事件

如何实现…

启动 Tizen IDE,创建一个新的 Tizen Web 应用程序项目,并为你计划使用的 API 在 config.xml 中添加所需的权限,例如 tizen.org/privilege/alarm

例如,以下 JavaScript 代码演示了如何简单使用 Alarm 和 Application API:

// Get the ID of the current application
var sAppId = tizen.application.getCurrentApplication().appInfo.id;

// Set an alarm which will occur after couple of hours
var myAlarm = new tizen.AlarmRelative(2 * tizen.alarm.PERIOD_HOUR);
if (null != myAlarm) {
  tizen.alarm.add(myAlarm, sAppId);
}

如何实现…

所有用于 Tizen Web 应用程序的额外设备 API 都是通过 tizen JavaScript 对象访问的。该对象还提供了一组通用函数,包括错误处理和过滤器。

Application API 用于获取当前应用程序的 ID,并将其赋值给 JavaScript 变量 sAppId。然后,使用 Alarm API 创建一个将在几个小时后发生的相对报警,并将其赋值给变量 myAlarm。最后,在代码片段的最后一行,报警被添加到当前应用程序的报警存储中。

如你所见,代码片段中使用的两个 API 都是通过 tizen JavaScript 对象访问的。

另见

  • 本章仅包含可用 API 的简要概述。大部分 API 的教程和示例可以在书籍第二部分的章节中找到。

Tizen Web 应用的本地化

应用程序的国际化和本地化到不同语言是成功的关键因素。本地化内容能够吸引更广泛的观众,这将带来更多的下载量,当然,也能带来更好的收入。

国际化是设计应用程序的过程,使其能够支持多种语言。 本地化是将特定的本地资源(例如翻译成不同语言的文本)添加到应用程序中的过程。

在这个教程中,你将学习如何使用基于文件夹的本地化技术在 Tizen Web 应用程序中支持多语言。

如何实现...

执行以下步骤以本地化 Tizen 应用程序:

  1. 打开应用程序的项目,并在 项目视图 中选择其根文件夹。

  2. 从 Tizen IDE 的主菜单中,导航至项目 | 本地化 | 本地化向导...,如以下截图所示:如何操作...

    启动本地化向导

  3. 本地化向导的第一个屏幕上,选择将要本地化的文件,然后点击下一步

  4. 可用语言列表中选择语言,并将其添加到已选择语言列表中。之后,点击下一步

  5. 通过检查文件名选择需要翻译成所选语言的文件,然后点击完成

    提示

    要在测试应用本地化期间更改 Tizen 设备或模拟器的全局语言,请导航至设置 | 语言和键盘 | 显示语言

它是如何工作的…

本地化向导会在应用包的根目录下创建一个名为locales的文件夹,并为每个选定的语言创建单独的文件夹。所有已选择进行本地化的文件将包含在其相应的文件夹中。例如,如果我们决定为index.html创建法语本地化,则会创建/locales/fr文件夹,并将该文件复制到其中。

如果没有选择某个文件进行本地化,它将不会出现在locales文件夹中,且会自动加载位于包根目录下的原始版本。

当网页应用启动时,Tizen 会尝试使用当前语言环境加载内容,该语言环境由用户在平台设置中配置。如果该语言环境不存在,则应用将使用其默认的本地化版本加载。

还有更多…

在 Tizen 网页应用中,通过 JavaScript 进行动态字符串本地化也是可能的,这得益于开源库Globalize。按照以下步骤启用并使用此库:

  1. 为每种支持的语言定义翻译表。例如,以下代码片段定义了默认语言(英语)和法语:

    Globalize.addCultureInfo("default", {
      messages: {
        "hello" : "Hello"
      }
    });
    
    Globalize.addCultureInfo("fr", {
      messages: {
        "hello" : "Bonjour"
      }
    });
    
  2. 使用以下方式的翻译字符串进行自动或手动语言选择:

    console.log(Globalize.localize("hello"));
    console.log(Globalize.localize("hello", "fr"));
    

请注意,消息是区分大小写的。在将显示语言设置为英语的 Tizen 设备或模拟器上的输出将如下所示:

Hello
Bonjour

了解更多关于开源库Globalize的信息,请访问github.com/jquery/globalize

打包 Tizen 网页应用

在成功开发和测试完网页应用后,所有的文件必须捆绑成一个名为package的单一文件,扩展名为.wgt。该包包含应用的所有 HTML、CSS、JavaScript 以及其他资源文件。.wgt文件用于在 Tizen 设备上安装网页应用,发布应用时应上传至 Tizen Store。

准备就绪

构建 Tizen 应用程序的工具已集成在 Tizen IDE 中。构建过程简单且完全自动化。在继续之前,请确保已正确安装 Tizen SDK 和 IDE。

注意

在开始打包 Web 应用程序之前,确保已设置活动的安全配置文件。如需更多信息,请阅读 第一章 中的配方 设置活动安全配置文件

如何操作...

执行以下操作以从 Tizen IDE 构建 Tizen Web 应用程序:

  1. 启动 Tizen IDE,进入项目资源管理器视图。选择应用程序的项目。

  2. 右键点击项目,选择项目 | 构建包

    注意

    通过检查项目文件夹的内容,确保包已成功创建。

工作原理...

Tizen IDE 创建的包是根据 W3C 对 Web 应用程序的推荐规范生成的。如需了解更多信息,请访问 www.w3.org/TR/widgets/

包的内容使用 ZIP 压缩算法进行压缩,文件扩展名必须为 .wgt。其 MIME 类型为 application/widget

以下表格显示的若干保留名称的文件和文件夹必须包含在 Tizen Web 应用程序的包中。成功安装后,在 /opt/usr/apps 下将创建一个与包 ID 匹配的目录。目录层次结构还包括文件夹 bin(用于应用程序的二进制文件)、datares

名称 描述
config.xml Web 小部件的配置。
icon.gif 支持多种文件类型作为 icon
icon.ico
icon.jpg
icon``.``png
icon.svg
index.html 支持几种文件类型作为主入口页面。默认情况下文件名为index
index.htm
index.svg
index.xhtml
index.htt
locales 包含本地化数据的目录。

Web 应用程序的保留目录和文件名

如果启用了开发者模式,可以通过 Tizen IDE 或命令行界面通过 SDB 安装 Web 应用程序。应用程序发布后,用户可以从Tizen Store或其他商店下载应用。

设备上的操作系统包管理器负责安装和管理已安装的应用程序。要查看所有已安装应用程序的列表,请启动设置并选择管理应用程序。单击应用程序以将其删除或停止正在运行的应用程序。

参见

  • 查看配方 Tizen 原生应用程序编程,了解如何创建多项目应用程序以及如何捆绑混合应用程序。

Tizen 原生应用程序编程

自 Tizen 2.0 以来,已经可以使用 C/C++ 编程语言开发移动应用程序。虽然在大多数情况下,应该优先选择并推荐使用 Web 应用程序,但本地编程对于更快的性能、低级别设备功能访问、与现有 Bada 应用程序的兼容性以及支持 Qt for Tizen 等第三方库和框架非常有用。Tizen 的本地编程同时支持服务应用程序和具有 GUI 的应用程序。

准备中

Tizen 的本地开发框架相当复杂。与标准 C++ 最显著的不同之处在于异常处理机制和两阶段构造函数。虽然 Tizen 不使用 C++ 异常,但您可以使用 try-catch 语句来处理您自己应用程序中的 C++ 异常。

Tizen 本地应用程序针对移动设备基于 Bada 的图形堆栈,这被称为本地框架或OSP(开放服务平台)。在将现有的 Bada C++ 应用程序移植时,OSP 命名空间应重命名为 Tizen。这个移植过程可以通过 Tizen IDE 很容易地完成。有关 Tizen 本地框架中可用命名空间的完整列表,请访问developer.tizen.org/dev-guide/2.2.1/org.tizen.native.apireference/namespaces.html

此外,Tizen 本地框架包含一些隐藏的宝藏,例如本地应用程序的特定生命周期和用于日志记录的宏。

如果您计划开发复杂的 Tizen 本地移动应用程序,请详细阅读本地开发文档。

如何操作...

按照以下指南创建一个简单的 Tizen 本地应用程序:

  1. 启动 Tizen IDE,如果出现提示,选择一个工作区。强烈建议将 IDE 切换为本地视图。

  2. 导航至文件 | 新建 | 项目...

  3. 创建项目的向导将出现。在不同项目类型的列表中,选择Tizen | 本地 Tizen 项目,然后点击下一步

  4. 模板中,选择Tizen 表单应用程序无 SceneManager。输入项目名称,例如helloWorldNative。然后,点击完成

  5. 项目视图中选择项目,并右键点击以打开包含附加选项的上下文菜单。选择运行本地 UI 构建器

  6. 等待 Tizen 本地 UI 构建器完全加载。选择大纲视图中的IDL_FORMHeader

  7. 转到本地 UI 构建器属性视图,并展开所有属性。将标题文本更改为Hello World如何操作...

    从 Tizen 本地 UI 构建器更改标题文本

  8. 保存更改并关闭本地 UI 构建器。

  9. 使用Tizen Manifest 编辑器打开manifest.xml,并选择功能选项卡。

  10. 点击 添加,选择 tizen.org/feature/screen.size.all 以支持所有屏幕尺寸,并确认你的选择。

  11. 确保连接了启用开发者模式的 Tizen 设备,或者模拟器正在运行。再次在 Tizen IDE 的项目视图中选择应用程序的项目,右键点击打开上下文菜单。导航至 作为运行 | Tizen 原生应用程序。另一种方式是直接点击运行按钮来部署并启动应用程序。

注意

第 9 步和第 10 步是可选的,但强烈建议执行,因为如果未指定屏幕尺寸特性,Tizen Store 可能会拒绝应用程序,并且在打包过程中会显示警告。

工作原理

按照此过程,Tizen IDE 将自动创建项目的文件系统以及 C++ 和资源文件。

原生 Tizen 移动应用程序的主类必须继承 Tizen::App::UiApp 类或 Tizen::App::ServiceApp 类。我们的示例继承了 Tizen::App::UiApp,并重载了多个方法,包括 OnAppInitializing()OnAppInitialized()

在原生应用启动后,首先调用的方法是 OnAppInitializing()。之后,OnAppInitialized() 也会被调用,并使用 AddFrame() 方法创建我们的示例应用程序的框架:

helloWorldFrame* phelloWorldFrame = new (std::nothrow) helloWorldFrame;
TryReturn(phelloWorldFrame != null, false, "The memory is insufficient.");
phelloWorldFrame->Construct();
phelloWorldFrame->SetName(L"helloWorldNative");
AddFrame(*phelloWorldFrame);

注意

每个具有 GUI 的 Tizen 原生应用程序必须至少有一个框架。

nothrow 语句作为 new 操作符的参数,用于创建 helloWorldFrame,以确保不会抛出异常。还要注意名称的硬编码字符串前缀 L。它表示该文本是 Unicode 字符串。

当应用程序运行时,每一帧可能处于以下三种状态之一:激活、停用或最小化。应用程序终止时,OnAppTerminating() 方法会被调用,所有资源必须释放。

通过 Tizen Native UI Builder 所做的头文件修改被保存为 XML 文件 IDL_FORM.xml。Native UI Builder 简化了这一过程,但如果手动编辑 XML 文件,也能达到相同效果。

另见

打包 Tizen 原生应用程序

成功开发和测试原生应用程序后,所有文件必须打包到一个单独的安装文件中,其扩展名为.tpk。此文件称为package。它听起来类似于Android 应用程序包文件(APK),并具有相同的目的。.tpk文件用于在 Tizen 设备上安装原生应用程序,并在应用程序发布时应上传到 Tizen Store。

准备工作

Tizen 还支持由 GUI 项目与一个或多个不具有 GUI 的服务应用程序项目组成的原生移动应用程序。这种类型的应用程序结合了多个项目的配置。

注意

在开始打包原生应用程序之前,请确保已设置活动的安全配置文件。有关详细信息,请参阅《第一章》的Setting Active Secure Profile配方从 ch01.html,《Tizen SDK》。

如何做到……

执行以下步骤以从单个项目创建 Tizen 原生移动应用程序的包。

  1. 在 Tizen IDE 的Project Explorer中定位应用程序项目,并选择它。

  2. 单击项目,然后从上下文菜单中选择Project > Build Package > TPK

  3. 最后,单击OK

注意

通过检查项目文件夹的内容来确保已成功创建包。

执行以下步骤以从多个项目创建 Tizen 原生移动应用程序的包。

  1. 在 Tizen IDE 的Project Explorer视图中打开应包含在包中的所有项目。

  2. Project Explorer中选择具有 GUI 的项目,右键单击它。

  3. 转到Properties | Project References

  4. 检查与 GUI 项目相关的服务应用程序项目。

  5. 单击OK,然后继续打包 GUI 项目。

注意

从多个项目创建的应用程序包含所有相关项目的二进制文件、资源和数据文件。该应用程序具有单个manifest.xml文件,并合并所有项目的配置。

工作原理……

Tizen 原生移动应用和 Tizen Web 应用程序均采用 ZIP 算法进行压缩。与 Web 应用程序不同,原生移动应用的扩展名为.tpk。包的 MIME 类型为application/x-tizen.package-archive。包的内容分布在以下目录中,这些目录的名称是保留的:

目录名称 描述
bin 应用程序的二进制文件
data 私有数据
info 元数据(包括manifest.xml
lib
res 资源
settings 设置
shared 共享资源

原生移动应用程序的保留目录

Tizen 包管理器负责安装、更新和卸载本地和 Web 应用的包。成功安装后,包会被提取到 /opt/usr/apps 目录中,但该目录结构与 Web 应用的结构略有不同。

要查看 Tizen 设备或模拟器上所有已安装的应用,请启动 设置,并进入 管理应用。要删除应用,请从列表中选择该应用,点击 卸载,并确认卸载。如果启用了开发者模式,还可以使用 SDB 删除应用。

成为 Tizen Store 卖家

Tizen Store 是 Tizen 平台的官方第一个应用市场。你可以在 Tizen Store 注册并发布你的应用,以触及用户并增加你的评价。

注意

作为一个开源平台,Tizen 也允许从其他商店安装应用。与 iOS 不同,Tizen 生态系统中支持多个商店的存在。

准备工作

在 Tizen Store 注册是免费的,不需要特别的准备。如果你计划申请商业状态并发布付费应用,请准备好扫描版的商业注册证书和银行账户详情。

如何操作...

要注册为 Tizen Store 卖家,你需要执行以下简单的操作:

  1. 启动你喜欢的网页浏览器,访问 seller.tizenstore.com

  2. 点击 立即注册

  3. 如果你是独立开发者,选择 作为私人卖家注册。如果你代表公司,选择 作为企业卖家注册

  4. 按照屏幕上的指示(四个步骤),并提供所需的信息,成功完成注册。

  5. 要发布付费应用,你需要获得商业状态。在注册的最后一步,点击 申请商业卖家状态 按钮,或者登录后访问你的个人资料页面。

它是如何工作的...

Tizen Store 由三星运营,注册免费。注册后,卖家必须申请商业状态,才能提供付费应用。

付费应用的收入分配为三星获得 30%,卖家获得 70%。顺便提一下,这是行业标准的收入分配,因为许多其他操作系统的应用商店也为发布者保留相同的分成比例。

卖家每月收到支付,如果到期金额至少为 $150。支持的支付方式有通过银行转账到注册的银行账户或通过 PayPal。

另见

发布应用到 Tizen Store

在完成开发、测试和打包应用程序后,您可以开始将其发布到市场。注册 Tizen Store,发布您的 Web 或原生应用程序,可以选择免费或付费内容。

准备就绪

在开始之前,强烈建议您查看 Tizen Store 的验证指南,该指南可以在卖家网站的指南部分找到。

应用程序验证过程非常严格。Tizen Store 的质量保证团队检查每个提交的应用程序,确保它正常工作。应用程序被拒绝会导致开发者的延误和损失,因此最好在开始开发之前就了解验证标准。

如何操作...

将您的 Tizen 应用程序上传并发布到 Tizen Store,五个简单步骤:

  1. 启动您最喜欢的网页浏览器,访问seller.tizenstore.com

  2. 点击添加新应用

  3. 填写基本信息,上传应用程序包,然后点击下一步继续。

  4. 显示信息页面,填写描述,添加标签等。准备好后,点击下一步

  5. 最终审核页面验证您输入的信息,如果一切正常,点击确认

提示

如果您有任何问题,并且希望直接联系 Tizen Store 的代表,请前往支持 | 我的问答,点击写信以开始新的讨论。

工作原理...

上传的应用程序经过 QA 团队的验证,如果批准,它将可以从 Tizen Store 下载。验证过程大约需要三天时间,分为两个阶段:初步检查动态分析,以及审核和最终确认。第一阶段检查 API 权限、安全问题、恶意软件等,自动完成。第二阶段是手动进行的。如果应用程序成功通过两个阶段的验证,其状态将更改为准备销售。否则,如果应用程序未能通过验证,将向卖家提供包含详细信息的报告。

另见

  • 有关应用程序提交过程的详细信息,请登录 Tizen Store 卖家网站,点击指南按钮进入用户手册。

第二部分:创建 Tizen Web 应用程序

构建用户界面

存储数据

创建多媒体应用

开发社交网络应用

管理通讯录和日历

通信

使用传感器

第三章. 构建用户界面

本章将涵盖:

  • 小部件概述

  • 创建按钮

  • 创建列表视图

  • 显示弹出窗口

  • 使用 Tizen 通知 API

  • 自定义外观和感觉

  • 在画布上绘制和书写文本

  • 使用 WebGL 创建 3D 对象

简介

本书的这一章专注于图形用户界面。它包含了使用 Tizen Web UI 框架和 jQuery Mobile 创建按钮、列表、弹出窗口和通知的教程。我们还将介绍一些提高用户友好性的提示,并分享如何更容易地定制应用程序设计。此外,还包括了在 HTML5 画布上绘制 2D 和 3D 对象的参考指南。

小部件概述

Tizen Web UI 框架基于多个开源 JavaScript 库和框架:jQuery、jQuery Mobile 和 Globalize。

如今,jQuery Mobile 是最受欢迎的移动设备优化 Web 应用框架之一,Tizen 依赖于它也不足为奇。该框架基于流行的 JavaScript 库 jQuery。jQuery Mobile 是 jQuery 基金会的开源项目,且在 MIT 许可下发布。

准备工作

使用 Tizen Web UI 框架构建的 Tizen Web 应用程序的页面结构与 jQuery Mobile 类似。一个典型页面包含:

  • 页头

  • 内容

  • 页脚

Tizen UI 框架提供的大多数小部件基于 jQuery Mobile。还有一些新设计的小部件,以与 Tizen 本地 UI 匹配的方式提供。

以下表格按字母顺序列出了截至 Tizen SDK 2.2.1 版本,Tizen UI 框架提供的所有小部件:

小部件 简要描述
自动分隔符 在列表项之间自动添加分隔符。jQuery Mobile 的列表也有类似的选项。
按钮 基本的推送按钮,继承自 jQuery Mobile。
复选框 显示标准复选框,用户可以选择是否选中。通常,多个复选框会被分组在一起,用户可以同时选择多个选项。此组件也来自 jQuery Mobile。
日期、时间或日期时间选择器 简化日期和/或时间输入的小部件。
可扩展列表 提供可扩展的列表视图。
快速滚动 简化滚动并加快滚动速度。
翻转开关 类似于单选按钮,显示一个带有两个选项的开关。例如:开/关。这个小部件在 jQuery Mobile 中也有类似的实现。
底部 从 jQuery Mobile 继承的一个基本小部件。它位于页面的底部。
画廊 用于显示图片的小部件。
3D 画廊 一个允许显示图片进行 3D 排列的小部件。
处理程序 为触摸屏设备优化的滚动条。
头部 jQuery Mobile 中的另一个基本小部件。它位于页面的顶部。
HTML 块 一个包含自定义 HTML 代码的小部件。
列表 具有多个项的列表视图,可以自定义外观。这个小部件与 jQuery Mobile 中的相同。
列表分隔符 列表中的一个特殊项,充当分隔符。它方便进行分组,同时也来自 jQuery Mobile。
多媒体视图 一个提供音频和视频播放器的小部件。
通知 当事件发生时显示的信息小部件。
弹出窗口 一个可自定义的小部件,用于在单独的窗口中显示信息。它具有与同名 jQuery Mobile 小部件相同的方法和事件。
进度 表示当前有一个操作正在进行。
进度条 使用百分比指示正在进行的操作的进度。这个小部件取自 jQuery UI。
搜索过滤栏 一个过滤器,简化了在大量文本数据中搜索的过程。这个小部件在 jQuery Mobile 中也存在。
滑块 另一个来自 jQuery Mobile 的小部件。它收集用户在开发者定义的范围内选择的值。
拆分视图 将内容拆分成多个不同的视图显示在屏幕上。
滑动 一个高级列表小部件,列表项可以滑动,并且按钮可以出现在每个项的位置。
标签栏 将按钮捆绑成一个组。建议将其放置在页面的头部或底部。
令牌文本区域 一个复杂的小部件,将用户输入的文本转换为按钮。
虚拟网格 一个优化加载和显示大量数据的表格小部件。
虚拟列表 一个优化加载和显示大量数据的列表小部件。

如何做到…

使用以下 HTML5 源代码创建一个页面,页面包含一个带有标题和按钮的头部,一个包含列表的内容和一个底部:

<div data-role="page">
  <div data-role="header" data-position="fixed">
    <h1>Tizen</h1>
    <div data-role="button" data-icon="plus" class="naviframe-edit">Add</div>
    </div>
  <div data-role="content">
    <ul data-role="listview">
      <li data-role="list-divider">Chapter 3</li>
      <li>Building UI</li>
      <li>Creating Buttons</li>
      <li>Creating List Views</li>
    </ul>
    </div>
    <div data-role="footer" data-position="fixed">
    <h4>Packt Publishing</h4>
  </div>
</div>

它是如何工作的…

HTML5 代码示例演示了基于 jQuery Mobile 的 Tizen UI Web 框架的使用方法。

一个页面是通过带有data-role属性和值“page”的div标签创建的。在 HTML 中,带有div关键字的标签用于定义文档的一个部分。头部和底部是以类似的方式创建的。头部包含一个标记为h1的标题和一个按钮,按钮的图标通过data-icon属性设置。data-icon的值应该与 jQuery Mobile 提供的可用图标集中的选项匹配。此示例使用的是plus

页面中的主要组件位于一个div元素中,该元素位于页头和页脚之间,并且该部分标记为data-role="content"。本食谱上一节的示例展示了列表和列表分隔符小部件的用法。

另请参见

创建按钮

本食谱展示了如何创建一个 Tizen Web 应用程序并创建按钮,如何处理用户点击这些按钮时的事件。

准备工作

Tizen UI Web 框架中的按钮可以通过以下三种方式中的任何一种来创建:

  • 使用 HTML5 元素,如anchordiv,并添加属性data-role="button"

  • 使用 HTML5 的button元素

  • 使用 HTML5 的input元素

注意

Tizen UI Web 框架基于 jQuery Mobile,类似的规则也适用于按钮。详细信息请访问developer.tizen.org/dev-guide/2.2.1/org.tizen.web.uiwidget.apireference/html/widgets/widget_button.htm

根据情况,您可以自由选择最适合您的方式来创建按钮。

现在我们准备好创建按钮了,让我们继续开发整个应用程序。

如何做...

  1. 启动 Tizen IDE,并启动一个新的 Tizen Web 项目。

  2. 使用 Tizen Web UI 框架创建单页面应用程序。

  3. 打开index.html,并用以下源代码替换body元素的内容:

    <div data-role="page">
      <div data-role="header" data-position="fixed">
        <h1>Buttons </h1>
      </div><!-- /header -->
      <div data-role="content">
        <p id="label">Please click a button.</p>
        <a id="btn1" href="#" data-role="button">Button 1</a>
        <button id="btn2">Button 2</button>
        <input type="button" id="btn3" value="Button 3" />
      </div>
      <div data-role="footer" data-position="fixed">
        <h4>Tizen Cookbook</h4>
      </div><!-- /footer -->
    </div><!-- /page -->
    
  4. 打开js/main.js,并将以下源代码附加到分配给变量init的 JavaScript 匿名(lambda)函数中:

    $('#btn1').bind( "click", function(event, ui) {
      $('#label').text('Button 1 clicked.');
    });
    
    $('#btn2').bind( "click", function(event, ui) {
      $('#label').text('Button 2 clicked.');
    });
    
    $('#btn3').bind( "click", function(event, ui) {
      $('#label').text('Button 3 clicked.');
    });
    
  5. 保存所有更改,并在真实设备、模拟器或仿真器上运行该应用程序。如果一切正常,当点击按钮时,带有id标签的段落文本将会被更改。

工作原理…

插入到index.html中的 HTML5 源代码创建了一个包含页头、页脚、带有id标签的单一段落和三个 ID 为btn1btn2btn3的按钮的页面。每个按钮都使用框架提供的不同选项之一创建,但视觉上它们看起来相同。

插入到 JavaScript 文件中的源代码基于 jQuery 库。第一行将 ID 为btn1的按钮的点击事件绑定到一个处理该事件的函数上。请看以下代码行:

$('#btn1').bind( "click", function(event, ui) {

美元符号是jQuery()的别名。这个函数根据提供的选择器返回 HTML 文档中元素的集合。此教程中的代码片段使用了 ID 选择器。jQuery 以其强大的 DOM 元素访问工具而著名。支持的选择器的完整列表可以在api.jquery.com/category/selectors/上找到。

下一行使用 jQuery 提供的text()方法来更改段落标签的文本。请看下面的代码行:

$('#label').text('Button 1 clicked.');

注意

需要注意的是,根据包含在 Tizen SDK 2.2.1 中的 jQuery Mobile 1.3.2 的文档,必须使用$(document).bind('pageinit')而不是$(document).ready()。请注意,在 jQuery Mobile 1.4 中,pageinit事件已被pagecreate替代。

如果事件处理程序没有绑定到按钮的适当位置,它们很可能无法正常工作。请注意,它们必须作为匿名函数实现,并分配给变量init。之后,init会绑定到pageinit事件,因此匿名函数将在页面初始化时执行。请看下面的代码行:

$(document).bind( 'pageinit', init );

匿名函数是 JavaScript 的第一类公民。它们最常用于回调函数——即在事件发生或稍后某个时间异步执行的函数。虽然这种使用匿名函数通常非常方便,但你需要注意它;否则,可能会陷入所谓的回调地狱。关于如何编写和维护易于阅读的 JavaScript 回调函数的良好建议,可以参考callbackhell.com/

另见

  • 本教程中示例应用程序的项目文件已经包含在书籍的源代码中。如果你在实现示例时遇到困难,请查阅其源代码。

创建列表视图

开发者中有一个流行的老笑话,认为没有列表的移动应用程序就不算好。这个控件对于存储大量数据非常方便,尤其是在屏幕较小的设备上,如智能手机或智能手表。

本教程解释了如何创建一个包含多个项目、项目分隔符和搜索过滤器的列表视图的多页面应用程序。

尽管多页面应用程序听起来很炫,但实际上它只是包含两个或更多 Tizen UI Web 框架页面的应用程序,而且创建这样的应用程序非常简单。

准备工作

Tizen UI Web 框架中的列表使用 HTML5 元素创建,分别是有序列表ol和无序列表ul,并结合data-role="listview"

如何做到……

  1. 创建一个新的项目,使用Tizen Web UI Framework多页面应用程序模板。

  2. 项目资源管理器中创建一个新的文件夹images

  3. 使用您的绘图应用程序创建一个简单的图标,并将其保存在 images 文件夹中,文件名为 smile``.``png

  4. 打开 Tizen IDE 中的 index.html,并用以下源代码替换 body 元素的内容:

    <div data-role="page" id="pageMain">
      <div data-role="header" data-position="fixed">
        <h1>List View</h1>
      </div><!-- /header -->
    
      <div data-role="content">
        <ul data-role="listview">
          <li data-role="list-divider">Samples</li>
          <li><a href="#pageInfo">Foo</a></li>
          <li><a href="#pageInfo">Bar <span data-role="button" data-inline="true" data-icon="arrow-r"></span></a></li>
            <li class="ui-li-has-multiline"><a href="#pageInfo"><img src="img/smile.png"
    class="ui-li-bigicon" />
    Foo
    <span class="ui-li-text-sub">Bar</span><span data-role="button" data-inline="true" data-icon="info"
    data-style="circle"></span></a></li>
        </ul>
      </div><!-- /content -->
      <div data-role="footer" data-position="fixed">
        <h4>Tizen Cookbook</h4>
      </div><!-- /footer -->
    </div><!-- /pageMain -->
    <div data-role="page" id="pageInfo" data-add-back-btn="true">
      <div data-role="header" data-position="fixed">
        <h1>Read-only List</h1>
      </div><!-- /header -->
      <div data-role="content">
        <ul data-role="listview">
          <li>baz</li>
          <li>qux</li>
        </ul>
      </div><!-- /content -->
      <div data-role="footer" data-position="fixed">
        <h4>Tizen Cookbook</h4>
      </div><!-- /footer -->
    </div><!-- /pageInfo -->
    
  5. 保存所有更改,并在模拟器或设备上运行应用。应用应显示如下:如何实现...

    列表视图

它是如何工作的...

前面示例应用中的 body 元素源代码只包含 HTML5 和 CSS。

两个页面被创建在两个不同的 div 元素中,每个页面都包含 data-role="page"。两个页面都包含页头、页脚和列表。

第一个页面的 id 标签为 pageMain。列表中的每个项是通过 li 元素创建的。该列表包含以下项:

  • 使用属性 data-role 的值为 list-divider 创建的列表分隔符。请查看以下代码行:

    <li data-role="list-divider">Samples</li>
    
  • 一个简单的项。请查看以下代码行:

    <li><a href="#pageInfo">Foo</a></li>
    
  • 一个在文本右侧带按钮的项。按钮是通过 span 元素创建的,具有默认样式,并通过属性 data-icon 设置了右箭头图标。请查看以下代码片段:

    <li><a href="#pageInfo">Bar <span data-role="button" data-inline="true" data-icon="arrow-r"></span></a></li>
    
  • 一个包含左侧图片(img)和右侧按钮的两行项。按钮的样式为 circle,图标为 info。CSS 类 ui-li-as-multiline 用于启用多行显示,ui-li-text-sub 类则标记第二行:

    <li class="ui-li-has-multiline"><a href="#pageInfo"><img src="img/smile.png"
    class="ui-li-bigicon" />
    Foo
    <span class="ui-li-text-sub">Bar</span><span data-role="button" data-inline="true" data-icon="info"
    data-style="circle"></span></a></li>
    

第二页显示了一个简单的只读列表,idpageInfo。显示在页脚的返回按钮实际上是通过 data-add-back-btn="true" 设置在页面的 div 元素上的:

<div data-role="page" id="pageInfo" data-add-back-btn="true">

另见

显示弹出窗口

你还记得那种丑陋的 JavaScript 内建函数 alert()confirm() 吗?虽然它们很有用,但它们的设计停留在 1990 年代,需要现代移动应用的替代品。

Tizen Web UI 框架提供了外观更好、设计可定制的弹出窗口,能够满足您的应用需求。在本教程中,我们将创建一个包含按钮的单页面应用,按钮点击后会弹出窗口。

如何实现...

  1. 启动 Tizen IDE,创建一个新的 Tizen Web 项目。

  2. 使用 Tizen Web UI 框架创建一个单页面应用。

  3. 打开 index.html,并用以下源代码替换 body 元素的内容:

    <div id="popupConfirm" data-role="popup" class="center_title_2btn">
      <div class="ui-popup-title">
        <h1>Mathematical Joke</h1>
      </div>
      <div class="ui-popup-text">There are only 10 types of people in the world: those who understand binary, and those who don't. Right?</div>
      <div class="ui-popup-button-bg">
      <a id="btnConfirmYes" href="#" data-rel="back" data-role="button" data-inline="true">Yes</a>
      <a id="btnConfirmNo" href="#" data-rel="back" data-role="button" data-inline="true">No</a>
       </div>
    </div>
    <div data-role="page">
      <div data-role="header" data-position="fixed">
        <h1>Showing Pop-ups</h1>
      </div><!-- /header -->
      <div data-role="content">
        <p id="label">Click the button below to open a pop-up.</p>
        <a href="#popupConfirm" id="btnConfirm" data-role="button">Push Me!</a>
      </div><!-- /content -->
      <div data-role="footer" data-position="fixed">
        <h4>Tizen Cookbook</h4>
      </div><!-- /footer -->
    </div><!-- /page 
    
  4. 打开 js/main.js,将以下源代码插入到分配给变量 init 的匿名 JavaScript 函数中。请查看以下代码:

    $('#btnConfirmYes').bind( "click", function(event, ui) {
      $('#label').text('Absolutely!');
    });
    $('#btnConfirmNo').bind( "click", function(event, ui) {
      $('#label').text('Sorry! It seems that you didn\'t get the binary joke.');
    });
    
  5. 运行应用,享受这段旧但经典的二进制笑话。

它是如何工作的...

第三步附加到index.html的 HTML5 代码包含一个页面和一个带有两个按钮的弹出窗口。该弹出窗口由具有id popupConfirmdata-role="popup"div元素表示。CSS 类center_title_2btn定义了它的类型。其他可用的类型如下:

  • center_info

  • center_title

  • center_basic_1btn

  • center_title_1btn

  • center_title_2btn

  • center_title_3btn

  • center_button_vertical

  • center_checkbox

  • center_liststyle_1btn

  • center_liststyle_2btn

  • center_liststyle_3btn

注意

除了center_button_vertical外,所有有多个按钮的类型中,按钮都会水平排列在一起。

附加到main.js中的 JavaScript 将处理程序绑定到弹出窗口的按钮上。根据用户的选择,具有id标签的段落文本内容会发生变化。

Tizen Web UI 框架和 jQuery Mobile 不支持弹出窗口的链式调用。这意味着无法从一个弹出窗口调用另一个弹出窗口。从设计角度来看,也不建议使用弹出窗口链式调用,因为它会对用户体验产生负面影响。不过,如果你坚持使用,可以通过在popupafterclose事件之后实现setTimeout(),在关闭第一个弹出窗口后,使用最短的超时来打开下一个弹出窗口。

另见

使用 Tizen 通知 API

通知 API 允许开发者向用户显示应用外的消息。当用户需要了解事件或正在进行的过程的状态时,通知就很有用。它们显示在一个共享的位置,供各个应用程序和系统的通知使用。

按照本教程中的步骤,学习如何使用 Tizen 通知 API 在 Tizen 中显示SIMPLEPROGRESS通知。

准备工作

Tizen 中存在几种不同类型的通知:

  • SIMPLE:这是一种基本文本通知

  • THUMBNAIL:该通知包含文本和缩略图

  • ONGOING:这是一种通知,告知用户应用程序是否正在运行

  • PROGRESS:这提供了关于任务当前状态及其进度的信息

前两种类型的通知可以由用户移除。其他类型的通知则无法由用户移除,应用程序应负责移除这些通知。通知 API 非常灵活,作为开发者,你可以选择完全符合应用需求的通知类型。

如何操作...

  1. 启动 Tizen IDE,创建一个新的 Tizen Web 项目。

  2. 使用 Tizen Web UI 框架创建单页应用程序。

  3. 将以下 HTML 代码插入到index.html的 body 中,以创建两个按钮:

    <div data-role="page">
     <div data-role="header" data-position="fixed">
     <h1>Using Tizen Notification API</h1>
     </div><!-- /header -->
    
     <div data-role="content">
     <button id="btnSimpleNotification">Simple Notification</button>
     <button id="btnProgressNotification">Progress Notification</button>
     </div><!-- /content -->
    
     <div data-role="footer" data-position="fixed">
     <h4>Tizen Cookbook</h4>
     </div><!-- /footer -->
    </div><!-- /page -->
    
    
  4. 将以下 JavaScript 函数粘贴到main.js中:

    function postSimpleNotification()
      {
        try {
          var notificationDict = {
            content: "Hello World."
          };
            simpleNotification = new tizen.StatusNotification("SIMPLE",
              "Notification", notificationDict);
              tizen.notification.post(simpleNotification);
        } catch (err) {
          console.log("Unable to post simple notification.");
        }
    }
    
    function postProgressNotification()
      {
        try {
          var notificationDict = {
            content: "Please wait..."
            };
            progressNotification = new tizen.StatusNotification("PROGRESS",
              "Progess", notificationDict);
              tizen.notification.post(progressNotification);
        } catch (err) {
          console.log("Unable to post progress notification.");
        }
    }
    
    function updateProgressNotification()
     {
    

    这个函数以及此处其他函数使用了 try-catch 块来处理异常,比如WebAPIException。如果发生错误,Notification API 的方法会抛出这些异常。

    try语句定义了一个代码块,在该块中应测试源代码是否有错误。必须使用关键字throw来抛出异常。异常终止了try块中源代码的执行,控制权传递给catch块。处理被拦截的异常的规则和命令在其中定义:

        try {
            progressNotification.content = "Almost done!";
            tizen.notification.update(progressNotification);
        } catch (err) {
            console.log("Unable to update progress notification.");
        }
    }
    
    function removeProgressNotification()
     {
      try {
        tizen.notification.remove(progressNotification.id);
      } catch (err) {
        console.log("unable to remove progress notification.");
      }
    }
    
    function runProgressDemo()
     {
      postProgressNotification();
    

    函数setTimeout()的第二个参数是延迟时间,单位为毫秒。6000 毫秒等于 6 秒,10000 毫秒等于 10 秒。请看以下代码:

    setTimeout(updateProgressNotification,6000);
    setTimeout(removeProgressNotification,10000);
    }
    
  5. 通过将以下代码片段插入分配给变量init的匿名 JavaScript 函数中,绑定两个按钮的点击事件到上一阶段的 JavaScript 函数:

    $('#btnSimpleNotification').bind( "click", function(event, ui) {
      postSimpleNotification();
    });
    
    $('#btnProgressNotification').bind( "click", function(event, ui) {
      runProgressDemo();
    });
    
  6. 将通知权限添加到config.xml

    <tizen:privilege name="http://tizen.org/privilege/notification"/>
    
  7. 保存所有修改过的文件,并运行应用程序。

它是如何工作的…

该应用程序包含一个单一应用和两个按钮。ID 为btnSimpleNotification的按钮的点击事件与 JavaScript 函数postSimpleNotification()绑定。当执行该函数时,屏幕上将显示一个标题为Notification,文本为Hello World的简单通知,如下所示:

它是如何工作的…

简单通知

点击 ID 为btnProgressNotification的按钮将执行函数runProgressDemo()。一个标题为Progress,文本为Please wait...的进度通知被发布。6 秒后,它将被更新,文本更改为Almost done!。该通知在发生后 10 秒被移除。函数updateProgressNotification()负责更新,函数removeProgressNotification()负责移除通知。这两个函数的执行延迟通过使用 JavaScript 内置函数setTimeout()来实现。你可以查看添加到main.js的所有函数实现,以了解 Notification API 的使用方式。请看以下截图:

它是如何工作的…

更新前后的进度通知

提示

可选地,通过在为通知创建的 JavaScript 对象中指定图像和/或音频文件的路径,可以添加图标和/或声音。

必须按照第 6 步所述添加权限,否则应用程序将无法正常工作,因为它将无法发布任何通知。使用设备或模拟器来测试和调试发布通知的应用程序。

另见

自定义外观和样式

你是否曾经遇到过这样的情况:客户在项目进行中间改变了需求,你不得不修改整个应用程序的设计?或者,你是否曾经遇到过需要将相同的应用程序交付给不同的客户,但他们有不同的主题和图片的情况?

CSS 是用于描述 Web 应用程序外观和格式的语言。每个 Web 开发人员都应该熟悉它。不幸的是,复杂的 CSS 文件的维护和修改可能会很困难。你总是可以在 Tizen Web 应用中使用 CSS,但在描述的这种情况中,最简单的解决方案是依赖于 CSS 预处理器,比如LESSSass

这个教程演示了 LESS 在 Tizen Web 应用中的基本用法。我希望通过这里获得的经验,你应该能够通过 LESS 生成复杂的 CSS。

准备工作

LESS 是一种开源的动态语言,它为 CSS 带来了变量、混合、操作和函数。LESS 可以通过 JavaScript 在客户端执行,也可以在服务器上执行。

注意

有效的 CSS 代码也是有效的 LESS 代码。

如何实现…

执行以下步骤从 LESS 在线生成 CSS。这个简单的示例更改了文本标题的字体和颜色:

  1. 使用你喜欢的网页浏览器加载网站less2css.org/

  2. 插入自定义颜色和字体的 LESS 源代码:

    @color1: #c0c0c0;
    @color2: #880000;
    @font: Arial, Helvetica, sans-serif;
    h1, h2, h3 {
      font-family: @font;
    }
    h1 {
      color: @color1;
      background-color: @color2;
    }
    h2 {
      color: @color2;
      background-color: @color2;
    }
    h3 {
      color: @color2;
    }
    

    提示

    请随意通过修改 LESS 变量的值来更改颜色。

  3. 将生成的 CSS 复制到剪贴板。CSS 应该类似于以下示例:

    h1, h2, h3 {
      font-family: Arial, Helvetica, sans-serif;
    }
    h1 {
      color: #c0c0c0;
      background-color: #880000;
    }
    h2 {
      color: #880000;
      background-color: #880000;
    }
    h3 {
      color: #880000;
    }
    
  4. 在 Tizen IDE 的项目资源管理器视图中选择一个项目,右键单击它,然后选择新建 | CSS 文件。按照屏幕上的指示完成文件的创建,文件名为myHeadings.css

  5. 将复制的内容粘贴到新创建的 CSS 文件中,并保存。

  6. index.html中添加以下 HTML 代码,将 CSS 文件作为外部样式表加载到应用程序中:

    <link rel="stylesheet" type="text/css" href="myHeadings.css">
    

注意

这个示例的优势在于,只需要修改变量的值,就可以改变所有标题的颜色。LESS 的真正威力可以在包含大量样式表的大型项目中体现出来。

它是如何工作的…

LESS 通过由开源项目 less-preview 提供的在线工具编译为 CSS。该项目的源代码可以在 GitHub 上找到,并且使用 MIT 许可证,维护者是 Brian Frichette。有关详细信息,请访问 github.com/brian-frichette/less-preview/

上述示例中的 LESS 代码片段非常简单。前面三行声明并初始化了 LESS 变量。根据规则,变量以前缀 @ 开头,后跟变量名。使用冒号来初始化其值。

字体系列通过 LESS 变量 @font 设置,其值在 h1h2h3 的 CSS 分组中设置:

h1, h2, h3 {
  font-family: @font;
}

其他 LESS 变量 @color1@color2 用于设置标题的字体和背景颜色。

成功执行 LESS 源代码的输出是有效的 CSS。当 CSS 准备好后,必须按照步骤 3 至 6 中的说明将其加载到 Tizen Web 应用中。

另见

  • 如果你有兴趣了解更多关于 CSS 预处理器的知识,可以通过 Alex Libby 编写的几本书来扩展你的知识:Instant SASS CSS How-toInstant LESS CSS Preprocessor How-to

在 canvas 上绘制和写入文本

HTML5 的主要优势之一是它可以替代 Adobe Flash 来进行绘图。HTML5 canvas 元素为在 Web 和移动应用程序或游戏中创建前沿动画开辟了新的视野。

本教程展示了在 Tizen Web 应用中使用 JavaScript 在 HTML5 canvas 上绘制和写入文本。按照本教程中的步骤创建一个包含两个按钮的单页面 Tizen Web 应用。第一个按钮写入文本 Hello Tizen,并绘制一个蓝色方块和一个橙色圆圈。第二个按钮清除屏幕。

在 canvas 上绘制和写入文本

在 Tizen Web 应用中绘制图形

准备工作

Canvas 是 HTML5 中引入的新元素。可以指定 canvas 的属性 idwidthheight。默认情况下,canvas 是空的,应该使用 JavaScript 来创建和控制其内容。

如何操作...

  1. 启动 Tizen IDE,并创建一个新的 Tizen Web 项目

  2. 使用 Tizen Web UI 框架创建 单页面应用程序

  3. 在项目资源管理器视图中右击项目,选择 新建 | 其他 | JavaScript | JavaScript 源文件 来创建 draw.js 文件。

  4. 将以下 JavaScript 代码保存到 draw.js 文件中:

    function draw()
    {
      var drawer = $('#pic')[0].getContext("2d");
      //write text
      drawer.fillStyle= '#000000';
      var nTextHeight = 20;
    

    HTML5 canvas 中的 font 属性支持与 CSS 字体相同的语法。Tizen 提供了一种专用的字体系列,称为 TizenSans,但在此应用程序中使用了流行的 Arial 字体。有关 Tizen 排版指南的更多信息,请访问 developer.tizen.org/documentation/ux-guide/visual-style/typography

      drawer.font= nTextHeight + "px Arial";
      drawer.fillText('Hello Tizen',0 , nTextHeight);
      //draw a blue square
      drawer.fillStyle= '#3366CC';
      var nSquareSide = 50;
      drawer.fillRect(0, nTextHeight+10, nSquareSide, nSquareSide);
      //draw an orange circle
      drawer.fillStyle='#FF6600';
      drawer.beginPath();
      var nRadius = 25;
      var nCenterX = nSquareSide + nRadius + 10;
      var nCenterY = nTextHeight + 10 + nRadius;
      drawer.arc(nCenterX, nCenterY, nRadius, 0, 2*Math.PI);
      drawer.fill();
    }
    
    function clear()
    {
      var canvas = $('#pic')[0];
      var drawer = canvas.getContext("2d");
      drawer.clearRect(0, 0, canvas.width, canvas.height );
    }
    
  5. index.html中,在加载main.js之前包含新的 JavaScript 文件。请查看以下代码:

    <script type="text/javascript" src="img/draw.js"></script>
    
  6. index.html 的 body 部分插入以下 HTML 来创建画布和几个按钮:

    <div data-role="page">
      <div data-role="header" data-position="fixed">
        <h1>Drawing Demo</h1>
      </div><!-- /header -->
    
      <div data-role="content">
        <canvas id="pic" width="200" height="200"></canvas>
        <button id="btnDraw">Draw</button>
        <button id="btnClear">Clear</button>
      </div><!-- /content -->
    
      <div data-role="footer" data-position="fixed">
        <h4>Tizen Cookbook</h4>
      </div><!-- /footer -->
    </div><!-- /page -->
    
  7. 通过向分配给main.jsinit变量的匿名 JavaScript 函数添加以下源代码来处理按钮点击事件:

    $('#btnDraw').bind( "click", function(event, ui) {
      draw();
    });
    $('#btnClear').bind( "click", function(event, ui) {
      clear();
    });
    
  8. 保存所有文件,并在设备或模拟器上运行应用程序。

工作原理……

index.html中创建了一个 ID 为pic、宽度和高度均为 200 px 的画布,代码如下:

<canvas id="pic" width="200" height="200"></canvas>

ID 为btnDrawbntClear的按钮的点击事件分别调用 JavaScript 函数draw()clear()。这两个函数都在文件draw.js中实现。

注意

index.html文件的head部分,必须在加载main.js之前加载draw.js,否则应用程序将无法正常工作。

JavaScript 函数draw()使用画布对象上的fillText()在屏幕上写入文本。之后,它调用画布对象的函数fillRect()并绘制一个边长为 25 px 的蓝色正方形。最后,执行函数arc()fill()来绘制一个半径为 25 px 的橙色圆圈。

提示

坐标 (0, 0) 对应绘图区域的左上角。

另见

  • 所有在 HTML5 画布上绘制的技巧都应该适用于 Tizen Web 应用程序。更多关于绘图和动画的 HTML5 示例可以在 Eric Rowell 的书《HTML5 Canvas Cookbook》中找到。

使用 WebGL 创建 3D 对象

二十年前,3D 图形和 OpenGL 主要仅限于 CAD 软件和游戏。那时的网站非常简单。时代变了,Web 技术有了显著发展。如今,得益于 WebGL,可以通过 JavaScript API 在 HTML5 画布中直接创建复杂的跨平台 3D 动画和游戏。

WebGL 的故事始于 2006 年,但它首次正式发布是在 2011 年。今天,一个名为 Khronos Group 的非盈利组织负责 WebGL 的标准。WebGL 基于 OpenGL ES,OpenGL 是一个高性能的 2D 和 3D 图形 API,而 ES 是它针对嵌入式设备的版本。WebGL 由 Khronos Group 发起的工作组维护,Apple、Google、Mozilla 等领先厂商的员工都是该工作组的成员。

这个高级示例演示了如何通过绘制一个在 Tizen Web 应用程序中顺时针旋转的立方体来创建 3D 动画。在启动应用程序后,用户必须点击播放按钮才能开始动画,如下图所示:

使用 WebGL 创建 3D 对象

WebGL 在 Tizen 上的演示

准备工作

此应用程序基于可在 Khronos Group 的公共 GitHub 存储库上找到的旋转 WebGL 盒子示例。根据其版权声明,本示例使用了由 Apple、Google 和 Khronos Group 版权所有的几个外部 JavaScript 文件。有关其许可证和使用条款的详细信息,请阅读每个文件开头的注释。

如何做...

  1. 启动 Tizen IDE,并开始一个新的 Tizen Web 项目。

  2. 使用 Tizen Web UI Framework 创建一个单页应用程序。

  3. 访问 Khronos Group 的 WebGL GitHub 存储库,网址为 github.com/KhronosGroup/WebGL,以查找、下载并保存以下文件到项目的 js 目录中:

    • webgl-utils.js

    • webgl-debug.js

    • J3DI.js

    • J3DIMath.js

  4. Project Explorer 视图中项目上右键单击,导航到 New | Other | JavaScript | JavaScript Source File,创建文件 draw.js

  5. 将以下 JavaScript 源代码插入到新创建的文件 draw.js 中。查看下面的代码:

    var g_nCurrentRotation = 360;
    var g_nRotationAngle = 1.0;
    var global = {};
    var g_nRequestId = 0;
    
    function setupColors(webGL)
    {
      var colors = new Uint8Array(
            [  0, 1, 0, 1,   0, 1, 0, 1,   0, 1, 0, 1,   0, 1, 0, 1, //main - green
               0, 0, 1, 1,   0, 0, 1, 1,   0, 0, 1, 1,   0, 0, 1, 1, // right - blue
               1, 0, 0, 1,   1, 0, 0, 1,   1, 0, 0, 1,   1, 0, 0, 1, //top - red
               1, 1, 0, 1,   1, 1, 0, 1,   1, 1, 0, 1,   1, 1, 0, 1, //left - yellow
               0, 0, 0, 1,   0, 0, 0, 1,   0, 0, 0, 1,   0, 0, 0, 1, // bottom - black
               0, 0, 0, 1,   0, 0, 0, 1,   0, 0, 0, 1,   0, 0, 0, 1 ]// back - black
                                                );
        // Set up the vertex buffer for the colors
        global.box.colorObject = webGL.createBuffer();
        webGL.bindBuffer(webGL.ARRAY_BUFFER, global.box.colorObject);
        webGL.bufferData(webGL.ARRAY_BUFFER, colors, webGL.STATIC_DRAW);
    }
    

    前面的代码片段声明了几个全局变量,并将它们初始化为默认值。它还包括一个名为 setupColors() 的函数,用于设置立方体每一面的颜色。下面的源代码实现了名为 init() 的函数,用于准备绘图区域,必须插入到同一文件中:

    function init()
    {
        var canvas = document.getElementById('screen');
        var webGL = WebGLUtils.setupWebGL(canvas);
        if (!webGL) {
          return;
        }
        global.program = simpleSetup(
            webGL, "vshader", "fshader",
            [ "vNormal", "vColor", "vPosition"], [ 1, 1, 1, 1 ], 10000);
    

    下面这行代码为着色器设置一个统一变量,它接受形状数据并将其转换为屏幕上的像素:

        webGL.uniform3f(webGL.getUniformLocation(global.program, "lightDir"), 0, 0, 1);
    
        global.box = makeBox(webGL);
    
        setupColors(webGL);
    

    将从类 J3DIMatrix4 创建的多个 4 x 4 矩阵用于 draw() 函数中的向量变换:

        global.mvMatrix = new J3DIMatrix4();
        global.u_normalMatrixLoc = webGL.getUniformLocation(global.program, "u_normalMatrix");
        global.normalMatrix = new J3DIMatrix4();
        global.u_modelViewProjMatrixLoc = webGL.getUniformLocation(global.program, "u_modelViewProjMatrix");
        global.mvpMatrix = new J3DIMatrix4();
    
        webGL.enableVertexAttribArray(0);
        webGL.enableVertexAttribArray(1);
        webGL.enableVertexAttribArray(2);
    
        webGL.bindBuffer(webGL.ARRAY_BUFFER, global.box.vertexObject);
        webGL.vertexAttribPointer(2, 3, webGL.FLOAT, false, 0, 0);
    
        webGL.bindBuffer(webGL.ARRAY_BUFFER, global.box.normalObject);
        webGL.vertexAttribPointer(0, 3, webGL.FLOAT, false, 0, 0);
        webGL.bindBuffer(webGL.ARRAY_BUFFER, global.box.colorObject);
        webGL.vertexAttribPointer(1, 4, webGL.UNSIGNED_BYTE, false, 0, 0);
    
        webGL.bindBuffer(webGL.ELEMENT_ARRAY_BUFFER, global.box.indexObject);
    
        return webGL;
    }
    

    下一个函数设置视口。最初,对象用建模坐标表示,然后转换为世界坐标,再转换为视图坐标,最终转换为视口坐标。因此,3D 场景被转换为在设备屏幕上显示的 2D 投影:

    function setupView(webGL)
    {
        var canvas = document.getElementById('screen');
        webGL.viewport(0, 0, canvas.width, canvas.height);
        global.perspectiveMatrix = new J3DIMatrix4();
        global.perspectiveMatrix.perspective(30, 1, 1, 10000);
        global.perspectiveMatrix.lookat(0, 0, 7, 0, 0, 0, 0, 1, 0);
    }
    

    现在是实现这些示例中最重要功能 draw() 的时候了。它负责绘制动画的每一帧。请将以下源代码附加到 draw.js 文件中:

    function draw(webGL)
    {
        setupView(webGL);
    

    在绘制任何东西之前,请确保画布是干净的。看看下面的代码片段:

        webGL.clear(webGL.COLOR_BUFFER_BIT | webGL.DEPTH_BUFFER_BIT);
    
        global.mvMatrix.makeIdentity();
        global.mvMatrix.rotate(20, 1,0,0);
        global.mvMatrix.rotate(g_nCurrentRotation, 0,1,0);
    
        global.normalMatrix.load(global.mvMatrix);
        global.normalMatrix.invert();
        global.normalMatrix.transpose();
        global.normalMatrix.setUniform(webGL, global.u_normalMatrixLoc, false);
    
        global.mvpMatrix.load(global.perspectiveMatrix);
        global.mvpMatrix.multiply(global.mvMatrix);
        global.mvpMatrix.setUniform(webGL, global.u_modelViewProjMatrixLoc, false);
    
        webGL.drawElements(webGL.TRIANGLES, global.box.numIndices, webGL.UNSIGNED_BYTE, 0);
    
        //Enable clockwise rotation
        g_nCurrentRotation -= g_nRotationAngle;
        if (0 > g_nCurrentRotation) {
            g_nCurrentRotation = 360;
        }
    }
    
    function pause(event) {
      event.preventDefault();
        if (undefined !== g_nRequestId) {
            window.cancelAnimFrame(g_nRequestId);
            g_nRequestId = undefined;
        }
    }
    
    function resume() {
        init();
        animate();
    }
    
    function run() {
        var canvas = document.getElementById('screen');
        canvas.addEventListener('webglcontextlost', pause, false);
        canvas.addEventListener('webglcontextrestored', resume, false);
    
        var webGL = init();
        if (!webGL) {
          return;
        }
    
        var animate = function() {
            draw(webGL);
            g_nRequestId = window.requestAnimFrame(animate, canvas);
        };
        animate();
    }
    
  6. 打开 index.html,并用以下代码替换它的内容:

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8"/>
        <meta name="description" content="WebGL 3D demonstration app for Tizen"/>
        <meta name="viewport" content="width=device-width,user-scalable=no"/>
    
        <link rel="stylesheet" href="tizen-web-ui-fw/latest/themes/tizen-white/tizen-web-ui-fw-theme.css" name="tizen-theme"/>
        <title>WebGL 3D</title>
        <script src="img/jquery.js"></script>
        <script src="img/tizen-web-ui-fw-libs.js"></script>
        <script src="img/tizen-web-ui-fw.js"
            data-framework-theme="tizen-white"></script>
        <script type="text/javascript" src="img/webgl-utils.js"></script>
        <script type="text/javascript" src="img/webgl-debug.js"></script>
    
        <script type="text/javascript" src="img/J3DI.js"></script>
        <script type="text/javascript" src="img/J3DIMath.js"></script>
    
        <script type="text/javascript" src="img/main.js"></script>
        <link rel="stylesheet" type="text/css" href="./css/style.css"/>
    

    在 HTML head 中插入以下两个脚本以实现一个顶点着色器,负责处理每个渲染三角形的每个角落:

        <script id="vshader" type="x-shader/x-vertex">
        uniform mat4 u_modelViewProjMatrix;
        uniform mat4 u_normalMatrix;
        uniform vec3 lightDir;
    
        attribute vec3 vNormal;
        attribute vec4 vColor;
        attribute vec4 vPosition;
    
        varying float v_Dot;
        varying vec4 v_Color;
    
        void main()
        {
            gl_Position = u_modelViewProjMatrix * vPosition;
            v_Color = vColor;
            vec4 transNormal = u_normalMatrix * vec4(vNormal, 1);
            v_Dot = max(dot(transNormal.xyz, lightDir), 0.0);
        }
        </script>
    

    下面的源代码实现了一个片段着色器。它在每个转换三角形的每个像素上应用纹理和光照:

        <script id="fshader" type="x-shader/x-fragment">
        precision mediump float;
    
        varying float v_Dot;
        varying vec4 v_Color;
    
        void main()
        {
            gl_FragColor = vec4(v_Color.xyz * v_Dot, v_Color.a);
        }
    
        </script>
    
        <script type="text/javascript" src="img/draw.js"></script>
    
    </head>
    

    继续通过附加 HTML body 的源代码如下。这将创建一个用户界面,通过几个按钮来控制动画:

    <body>
        <div data-role="page">
            <div data-role="header" data-position="fixed">
                <h1>WebGL 3D</h1>
            </div><!-- /header -->
    
            <div data-role="content" style="background-color: #FFFFFF;">
                <button id="btnPlay">Play</button>
                <canvas id="screen" width="200" height="200"></canvas>
            </div><!-- /content -->
    
            <div data-role="footer" data-position="fixed">
                <h4>Tizen Cookbook</h4>
            </div><!-- /footer -->
        </div><!-- /page -->
    </body>
    </html>
    
  7. 打开 main.js 并将函数 run() 注册为按钮 Play 的处理程序,如下所示:

    $('#btnPlay').bind( "click", function(event, ui) {
        run();
        $('#btnPlay').button( "disable" );
    });
    
  8. 保存所有更改,并在 Tizen 设备或模拟器上运行应用程序。

注意

本项目的完整源代码随书提供。该应用已在 Tizen 2.2.1 版本的设备上成功测试。

它是如何工作的…

所有外部 JavaScript 文件都在index.html的头部加载。步骤 3 中下载的文件提供了基本功能,简化了 WebGL 的常见使用。顶点和片段着色器的脚本也在index.html中,ID 分别为vsharedsfshaders

页面主内容的div元素上放置了 ID 为btnPlay的按钮和 ID 为screen的画布。画布用作绘图区域,其宽度和高度均为 200 px。

动画在点击btnPlay按钮时开始,按钮随之变为禁用。动画的入口点是 JavaScript 函数run(),它在draw.js文件中实现。通过同一文件中的init()函数初始化 WebGL 上下文。此外,pause()resume()函数分别绑定到画布的webglcontextlostwebglcontextrestored事件。

当前的旋转状态存储在全局 JavaScript 变量g_nCurrentRotation中,初始值为 360。每次动画的旋转角度由另一个全局 JavaScript 变量g_nRotationAngle定义。

提示

增加g_nRotationAngle的值以加快旋转速度,减少该值则会减慢旋转速度。

通过函数makeBox()创建立方体,并通过 JavaScript 函数draw()在屏幕上绘制它。它按顺时针方向旋转,因此每次执行draw()时,角度会从当前状态中减去。当g_nCurrentRotation的值低于 0 时,会重新设置为 360,动画重新开始。在draw()的开始部分,通过函数clear()清除画布,立方体则通过drawElements()函数显示。

立方体各面的颜色在setupColors()函数中设置。如果你想更改颜色,可以编辑数组colors中的值。前面的示例使用了纯色,如果你愿意,也可以为每一面设置不同的渐变。背景色是白色,它被设置为页面内容 HTML div元素的样式,并作为simpleSetup()函数的参数,该函数由init()函数调用。

另见

第四章:存储数据

本章将涵盖:

  • 写入文件

  • 读取文件

  • 创建一个简单的文本编辑器

  • 下载文件

  • 使用 Web 存储

  • 创建 Web SQL 数据库

  • 在 Web SQL 数据库中执行查询

  • 从 Web SQL 数据库中检索数据

  • 使用 IndexedDB

介绍

数据管理在现代世界中变得越来越重要。市场上已经存在数十亿互联网连接的移动设备和可穿戴设备。现在,下一大挑战是改善这些设备之间的通信和数据同步,同时提供更好的用户体验。每一代新的移动设备都有更大的内存,同时云服务的普及度也在不断增加。如今,存储和管理信息比以往任何时候都更为重要。

本章提供了关于在 Tizen 设备上存储和访问数据的技术细节。内容包括文件管理、Web 存储和 Web SQL 数据库 API 文章,以及关于通过互联网下载文件的教程。

正在写入文件

可以通过文件系统 API访问 Tizen 设备上的文件。平台的文件系统被划分为多个虚拟根目录:

  • documents

  • images

  • videos

  • music

  • ringtones

  • wgt-package

  • wgt-private

  • wgt-private-tmp

位于前面列表中的任何虚拟路径之外的文件仍然可以通过它们的 URI 从实际根目录访问。例如,目录 /etc/ 的 URI 是 file:///etc

API 支持四种模式来打开文件:

  • r:此模式仅以读取方式打开文件。

  • rw:此模式以读写方式打开文件。

  • w:此模式仅以写入方式打开文件。

  • a:此模式以写入方式打开文件,并将光标定位到文件末尾。新数据将追加到文件的现有内容后面。

本配方中的代码示例展示了如何创建文本文件并保存数据。由于在这些特定情况下不会读取文件内容,因此仅使用 wa 模式是合适的。

正在准备

使用文件系统 API 保存数据到文件需要权限。在开始之前,请确保已将以下权限添加到项目的 config.xml 文件中:

tizen.org/privilege/filesystem.write

如何操作……

按照这些说明,使用 Tizen 文件系统 API 将文本保存到文件:

  1. 使用以下代码片段,通过获取与 documents 虚拟路径相关联的对象来准备文件操作:

    var documentsDir;
    
    function onError(e) {
      console.log('error: ' + e.message);
    }
    
    function onResolveSuccess(dir) {
      documentsDir = dir;
    }
    
    tizen.filesystem.resolve('documents', onResolveSuccess, onError, 'w');
    
  2. 执行函数 createFile() 来创建一个空文件。文件名必须作为参数传递给该函数,例如 foo.txt

    try {
      documentsDir.createFile('foo.txt');
    }
    catch (err) {
      console.log('Unable to create file: '+err);
    }
    
  3. 实现一个回调函数,将文本 bar 写入与文件相关联的流:

    function write(fileStream) {
      try {
        fileStream.write('bar');
        fileStream.close();
      } catch (err) {
        console.log('Unable to save file: ' + err.message);
      }
    }
    
  4. 打开在第二步创建的文件,通过前一步实现的回调函数写入并保存数据,如下所示:

    try {
      file = documentsDir.resolve('foo.txt');
      file.openStream('w', write, onError);
    } catch (errWrite) {
      console.log('Unable to open file for writing: ' + errWrite.message);
    }
    

它是如何工作的……

Tizen 文件系统 API 是异步工作的,因此许多函数通过回调执行。成功的情况以及错误的情况都通过回调来处理。不要假设一切都会按预期工作,必须小心处理错误。

一个全局的 JavaScript 对象 documentsDir 在回调函数 onResolveSuccess() 中被初始化。之后,剩余的文件操作通过调用与该对象相关的函数完成。如果在执行过程中出现任何错误,函数 createFile()resolve()openStream() 都会抛出异常。重要的是要添加 try-catch 块,并正确处理潜在的异常。请注意,在这个示例中,任何可能发生的异常都会记录到控制台。在实际应用中,您应将错误报告与用户界面集成,并使其更加友好。

函数 write() 将数据保存到文件流中,然后关闭它。该函数是异步执行的,成功执行 openStream() 后会作为回调被调用。

读取文件

Tizen 文件系统 API 提供了几种不同的方式来读取文件。主要选项是使用文件流,另一种方式是通过函数 readAsText() 获取文件的全部内容作为字符串。两种方法都是异步的,并且都需要一个回调函数来成功完成,以及另一个函数来处理潜在的错误。

请记住,文件系统 API 是特定于 Tizen 的,其功能必须通过 JavaScript 对象 tizen.filesystem 来访问。

准备工作

在开始编码之前,请确保已将读取文件的权限添加到项目的 config.xml 文件中,如下所示:

tizen.org/privilege/filesystem.read

如何操作...

请按照以下两个步骤使用流从文件中读取文本:

  1. 准备一个表示 documents 目录的对象:

    var documentsDir;
    
    function onError(e) {
      console.log('error: ' + e.message);
    }
    
    function onResolveSuccess(dir) {
      documentsDir = dir;
    }
    tizen.filesystem.resolve('documents', onResolveSuccess, onError, 'w');
    
  2. 使用以下代码片段通过流读取文件内容。这种方法允许我们分块读取文件,并且比一次性读取整个文件消耗更少的内存:

    function read(fileStream) {
      try {
        var sFileContent = fileStream.read(fileStream.bytesAvailable);
        console.log('file content: ' + sFileContent);
        fileStream.close();
      } catch (err) {
        console.log('Unable to read file: ' + err.message);
      }
    }
    
    function readFile()
    {
      try {
        file = documentsDir.resolve('foo.txt');
      } 
      catch (exc) {
        return;
      }
    
      try {
        file.openStream('r', read, onError);
      } catch (err) {
        console.log('Unable to open file for reading: ' + err.message);
      }
    }
    

如果你更喜欢不使用流而直接读取整个文本文件的内容,你应该使用函数 readAsText(),如下示例所示:

function showFileContent(data) {
  console.log(data);
}

function readFileWithoutStream() {

  var file;
  try {
    file = documentsDir.resolve('foo.txt');
  } 
  catch (err) {
    return;
  }

  try {
    file.readAsText(showFileContent, onError);
  } catch (err) {
    console.log('Error reading file without a stream:' + err.message);
  }
}

它是如何工作的...

你可能已经注意到,读写文件的第一个步骤是创建一个表示工作目录的对象。在这个示例中,所使用的目录的虚拟根是 documents

读取文件的第一种方法依赖于流。Tizen 提供了一个叫做 FileStream 的接口,用于读写操作。

最重要的函数是 openStream()。必须将几个回调函数作为它的参数传递。第一个函数会在文件内容成功读取时被调用。在前面的示例中,这个函数的名称是 readFile()。第二个参数是一个函数,它会在出现错误时被调用。

函数 readFile() 接收文件流作为参数,尝试了解可用数据的大小,然后尝试使用 FileStream 接口的 read() 函数读取数据。

另一种方法不依赖于流,但仍然使用作为参数传递给 readAsText() 的回调函数。执行成功时,所有数据会传递给一个回调函数,在我们的示例中,该函数名为 showFileContent()

如果你愿意,也可以实现匿名的 JavaScript 回调函数。

读取文件的代码片段(包括使用流和不使用流的)都在失败时调用相同的函数 onError()。在本教程中,这个回调函数的实现非常简单,它只是将错误信息打印到 Web 控制台。

注意

无论你更倾向于哪种读取文件的方法,必须包含读取文件的权限。

另请参见

  • 下一个教程将介绍如何创建一个简单的文本编辑器,并一步步指导你在应用程序中实现使用流的文本文件读取和写入。

创建一个简单的文本编辑器

本教程提供了如何基于前面教程中关于文件读取和写入的知识创建一个简单文本编辑器的指南。示例应用程序的源代码简单易懂。

文本文件的内容在应用程序启动时加载到 textarea 中。用户可以修改文本,然后点击屏幕顶部的 保存 按钮,将其保存到相同的文件中。

如何操作...

按照以下步骤创建一个简单的 Tizen 文本编辑器:

  1. 启动 Tizen IDE 并开始一个新的 Tizen Web 项目。

  2. 使用 Tizen Web UI Framework 创建单页应用程序。

  3. 使用 Widget 配置编辑器打开 config.xml 文件,并选择 权限 选项卡。点击 添加 按钮并选择以下内部权限:

    tizen.org/privilege/filesystem.read

    tizen.org/privilege/filesystem.write

  4. 更新 index.html 文件的内容,使其与以下代码匹配:

    <!DOCTYPE html>
    <html>
    
    <head>
      <meta charset="utf-8"/>
      <meta name="description" content="Simple text editor for Tizen."/>
      <meta name="viewport" content="width=device-width,user-scalable=no"/>
    
      <link rel="stylesheet" href="tizen-web-ui-fw/latest/themes/tizen-white/tizen-web-ui-fw-theme.css" name="tizen-theme"/>
      <title>Simple Text Editor</title>
      <script src="img/jquery.js"></script>
      <script src="img/tizen-web-ui-fw-libs.js"></script>
      <script src="img/tizen-web-ui-fw.js"
     data-framework-theme="tizen-white"></script>
      <script type="text/javascript" src="img/file.js"></script>
      <script type="text/javascript" src="img/main.js"></script>
      <link rel="stylesheet" type="text/css" href="./css/style.css"/>
    </head>
    
    <body>
      <div data-role="page">
        <div data-role="header" data-position="fixed">
          <h1>Simple Text Editor</h1>
        </div><!-- /header -->
    
        <div data-role="content">
          <a href="#" id="btnSave" data-role="button" data-icon="check">Save</a>  
          <textarea id="textbox"></textarea>  
        </div><!-- /content -->
    
        <div data-role="footer" data-position="fixed">
         <h4>Tizen Cookbook</h4>
        </div><!-- /footer -->
      </div><!-- /page -->
    </body>
    </html>
    
  5. 右键点击 项目浏览器 视图中的项目,依次选择 新建 | 其他 | JavaScript | JavaScript 源文件,然后创建 file.js 文件。

  6. 打开 file.js 并插入以下源代码:

    var documentsDir;
    
    var sTxtFile = 'simpleTextFile.txt';
    
    function onError(e) {
      console.log('error: ' + e.message);
    }
    
  7. 在同一个源文件中实现 JavaScript 函数,以通过文件流读取和写入数据。请查看以下代码:

    function read(fileStream) {
      try {
      $('#textbox').val(fileStream.read(fileStream.bytesAvailable));
        fileStream.close();
      } catch (err) {
        console.log('Unable to read file: ' + err.message);
      }
    }
    
    function write(fileStream) {
      try {
        fileStream.write($('#textbox').val());
        fileStream.close();
      } catch (err) {
        console.log('Unable to save file: ' + err.message);
      }
    }
    
  8. 声明一个函数 loadFile(),如果文件存在,它会将文件内容加载到文本区域中,代码如下:

    function loadFile()
     {
      try {
        file = documentsDir.resolve(sTxtFile);
      } 
      catch (exc) {
        return;
      }
    
      try {
        file.openStream('r', read, onError);
      } catch (err) {
        console.log('Unable to open file for reading: ' + err.message);
      }
    }
    
    function onResolveSuccess(dir) {
      documentsDir = dir;
      loadFile();
    }
    
  9. 将 JavaScript 函数 createFile()saveFile() 附加到文本文件中,通过这些函数可以保存内容,代码如下:

    function createFile()
     {
      try {
        documentsDir.createFile(sTxtFile);
        file = documentsDir.resolve(sTxtFile);
    }
      catch (err) {
        console.log('Unable to create file: '+err.message);
        return false;
      }
      return true;
    }
    
    function saveFile()
     {
      var bFileExists = true;
      try {
        file = documentsDir.resolve(sTxtFile);
      } 
      catch (errFile) {
        if (false == createFile()) {
          return;
        }
      }
    
      try {
        file.openStream('w', write, onError);
      } catch (errWrite) {
        console.log('Unable to open file for writing: ' + errWrite.message);
      }
    }
    
  10. 将以下代码片段附加到 main.js 文件中的初始化函数:

      tizen.filesystem.resolve('documents', onResolveSuccess, onError, 'rw');
    
      $('#btnSave').bind( "click", function(event, ui) {
        saveFile();
      });
    
  11. 保存所有更改,构建应用程序,并在 Tizen 模拟器或设备上运行它。

注意

这个示例使用 console.log() 打印在应用执行过程中可能发生的错误。这些信息仅在控制台输出,目的是简化调试。请注意,不建议在生产代码中保留 console.log()。它仅作为一个简单的错误处理技巧,在这个示例中使用。你可以通过弹出框或通知来显示错误信息。

它是如何工作的...

该示例依赖于 Tizen 文件系统 API 来创建、读取和写入文件。第三步中设置的权限是强制性的。没有这些权限,将会抛出 WebAPIException 异常,错误类型为 SecurityError,应用程序将无法按预期工作。

简单文本编辑器的用户界面有一个按钮和一个输入框。如果文档目录成功解析,loadFile() 函数将在应用启动时被调用。它以只读方式打开 simpleTextFile.txt,异步获取其内容,并加载到文本区域。

每次点击 保存 按钮时,都会调用 saveFile() 函数。它打开 simpleTextFile.txt 进行写入,并将其数据替换为 HTML5 textarea 中 ID 为 textbox 的内容。如果文件不存在,则 saveFile() 会通过执行 createFile() 函数尝试创建文件。

文件的读取和写入是通过文件流和回调函数异步实现的。操作成功完成后,文件流会被关闭。

文本文件的名称存储在全局变量 sTxtFile 中,该变量由所有函数使用。该文件位于文档的虚拟根目录。请查看下面的截图:

它是如何工作的...

一个用于 Tizen 的简单文本编辑器

另请参见

下载文件

Tizen 提供了一个 下载 API,专门用于从远程服务器的 URL 异步传输数据到设备的存储。这一 API 非常灵活,但仍然易于使用。例如,开发者可以明确指定是否为特定下载使用蜂窝数据或 Wi-Fi 连接。在下载过程中,文件具有以下状态之一:QUEUEDDOWNLOADINGPAUSEDCANCELEDCOMPLETEDFAILED

这个 API 的使用将通过一个示例应用程序演示,该应用程序下载 PNG 和 JPEG 图像并将其保存到为图像定义的文件系统位置。

准备工作

必须在 Tizen 应用程序中授予权限tizen.org/privilege/download才能使用下载 API。如果应用没有所需的权限,执行接口DownloadManagerstart()函数时会抛出异常。

如何操作……

通过执行以下步骤创建一个 Tizen Web 应用来下载图片:

  1. 启动 Tizen IDE 并创建一个新的 Tizen Web 项目。

  2. 从向导的可用选项中选择Tizen Web UI 框架单页面应用

  3. 使用小部件配置编辑器打开config.xml文件,选择权限选项卡,点击添加按钮。插入以下内部权限:

    tizen.org/privilege/download

  4. 用以下源代码替换index.html的内容:

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8"/>
        <meta name="description" content="Tizen application for downloading PNG and JPEG images."/>
        <meta name="viewport" content="width=device-width,user-scalable=no"/>
    
        <link rel="stylesheet" href="tizen-web-ui-fw/latest/themes/tizen-white/tizen-web-ui-fw-theme.css" name="tizen-theme"/>
        <title>Image Download</title>
    
        <script src="img/jquery.js"></script>
        <script src="img/tizen-web-ui-fw-libs.js"></script>
        <script src="img/tizen-web-ui-fw.js"
            data-framework-theme="tizen-white"></script>
    
        <script type="text/javascript" src="img/download.js"></script>
        <script type="text/javascript" src="img/main.js"></script>
        <link rel="stylesheet" type="text/css" href="./css/style.css"/>
    </head>
    
    <body>
        <div data-role="page">
            <div data-role="header" data-position="fixed">
                <h1>Image Download</h1>
            </div><!-- /header -->
    
            <div data-role="content">
            <label for="inputImageURL">Image URL:</label>
            <input type="text" name="inputImageURL" id="inputImageURL" value="" />  
          <a href="#" id="btnDownload" data-role="button">Download</a>
          <p id="label"></p>
            </div><!-- /content -->
    
            <div data-role="footer" data-position="fixed">
                <h4>Tizen Cookbook</h4>
            </div><!-- /footer -->
        </div><!-- /page -->
    </body>
    </html>
    
  5. 通过右键点击项目资源管理器视图,打开上下文菜单,导航至新建 | 其他 | JavaScript | JavaScript 源文件,并创建文件download.js

  6. 打开download.js并将以下代码附加到其中:

    var nDownloadImageId = 0;
    var bIsPause = false;
    
    function checkFileExtension(sFilename) {
      sFileExtension = sFilename.split('.').pop().toLowerCase();
      var extensions = ['png', 'jpg', 'jpeg'];
      if ( -1 == extensions.indexOf(sFileExtension) )
      {
        return false;
      }
      return true;
    }
    
    function reset() {
      bIsPause = false;
      nDownloadImageId = 0;
      $('#btnDownload').text('Download');
    }
    
  7. 实现一个监听器来处理下载事件:

    var listener = 
    {
      onprogress: function(id, receivedSize, totalSize) 
      {
        var nDownloadProgress = Math.round( (receivedSize / totalSize) * 100);
        $('#label').text(nDownloadProgress+'% completed');
      },
    
      onpaused: function(id) 
      {
        bIsPause = true;
        $('#btnDownload').text('Resume');
      },
    
      oncanceled: function(id) 
      {
      },
    
      oncompleted: function(id, sFullPath) 
      {
        $('#label').text('Image saved as: ' + sFullPath);
        nDownloadImageId = 0;
        $('#btnDownload').text('Download');
      },
    
      onfailed: function(id, error) 
      {
        $('#label').text('Download failed: ' + error.name);
        reset();
      }
    };
    
    function handleButton() {
      if (0 == nDownloadImageId) {
        var sURL = $('#inputImageURL').val();
        if (false == checkFileExtension(sURL)) {
          throw "PNG and JPG files allowed only.";
        }
        var downloadRequest = new tizen.DownloadRequest(sURL, "images");
        nDownloadImageId = tizen.download.start(downloadRequest, listener);
    
        $('#btnDownload').text('Pause');
      }
      else if (true == bIsPause) {
        tizen.download.resume(nDownloadImageId);
        bIsPause = false;
        $('#btnDownload').text('Resume');
      }
      else {
        tizen.download.pause(nDownloadImageId);
        $('#btnDownload').text('Pause');
      }
    }
    
  8. 将以下代码片段附加到main.js文件中的初始化函数:

    $('#btnDownload').on( "click", function(event, ui) {
      try {
        handleButton();
      }
      catch(err){
        $('#label').text(err);
        reset();
      }
    });
    
  9. 保存所有更改。在 Tizen 模拟器或设备上构建并运行应用。

它是如何工作的……

当应用启动时,用户必须输入图片的 URL 并点击下载按钮。允许的文件扩展名有pngjpgjpeg。其他扩展名不允许启动下载。用户可以在下载过程中通过点击下载按钮暂停和恢复下载。

成功下载的图片会存储在图片虚拟根目录中,可以直接从 Tizen 默认的画廊应用访问。

在这个简单示例中,唯一按钮的 ID 是btnDownload。在main.js文件中,它的点击事件与一个匿名函数关联,该函数调用handleButton()。被调用的函数在download.js文件中实现,并且根据应用的状态有不同的行为。

全局变量nDownloadImageId存储正在进行的下载的 ID。如果没有下载进行中,其值为零。全局布尔变量bIsPause表示当前下载是否已被暂停。

下载从函数handleButton()中的以下两行代码开始,其标识符存储为nDownloadImageId

var downloadRequest = new tizen.DownloadRequest(sURL, "images");
nDownloadImageId = tizen.download.start(downloadRequest, listener);

start() 函数接受一个对象作为参数,其中包含下载请求的详细信息以及一个可选的下载回调函数。DownloadRequest 接口构造函数的唯一必需参数是 URL;其他参数(如目标位置、保存文件的名称和网络连接类型)是可选的。下载回调处理 onprogress()onpaused()oncanceled()oncompleted()onfailed() 事件。有关更多详细信息,请参考 DownloadCallback 接口的文档 developer.tizen.org/dev-guide/2.2.1/org.tizen.web.device.apireference/tizen/download.html#::Download::DownloadCallback

另请参阅

  • 请查看文件系统 API 的文档,了解最合适的虚拟路径以存储下载的文件。将文件存储在合适的位置有助于提升用户体验,因为这些文件不仅可以方便地通过系统应用访问,而且能够轻松定位。例如,照片共享或图形编辑应用会在图像目录中查找文件。

  • 有关 Tizen SDK 2.2.1 中下载 API 的更多信息和详细内容,请访问 developer.tizen.org/dev-guide/2.2.1/org.tizen.web.device.apireference/tizen/download.html

使用 Web 存储

Tizen Web 应用程序可以充分利用 HTML5 Web 存储。保存在 localStorage 中的数据会永久存储在设备的内存中,而保存在 sessionStorage 中的数据则会在应用程序运行期间临时保存。在 Tizen 中,sessionStorage 的大小是无限的,而本地存储(localStorage)最多可以存储 5 MB 的数据。这两种存储类型都实现了 storage 接口,因此可以使用相同的数据操作方法,具体如下:

  • key(n):此方法返回与提供的参数中指定数字位置相匹配的存储数据项的名称。

  • getItem(key):此方法返回与提供的键相对应的值。

  • setItem(key, value):此方法将一个键值对保存到存储中。

  • removeItem(key):此方法根据提供的键查找并删除存储中的元素。

  • clear():此方法删除存储对象中的所有键值对。

注意

请注意,Web 存储是 HTML5 中的一个标准 API,因此在 Tizen 应用程序中使用它不需要任何特权。

本教程演示了如何创建一个使用 localStorage 永久存储文本笔记的应用程序,并且如何利用 sessionStorage 提供撤销功能。

如何实现...

按照此指南创建一个使用 Web 存储的 Tizen Web 应用程序:

  1. 启动 Tizen IDE 并开始一个新的 Tizen Web 项目。

  2. 在新项目向导中,首先选择 Tizen Web UI Framework,然后选择 单页面应用程序

  3. 打开 index.html 并将其源代码替换为以下 HTML5 代码:

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8"/>
        <meta name="description" content="Web storage demo app."/>
        <meta name="viewport" content="width=device-width,user-scalable=no"/>
    
        <link rel="stylesheet" href="tizen-web-ui-fw/latest/themes/tizen-white/tizen-web-ui-fw-theme.css" name="tizen-theme"/>
        <title>NoteApp</title>
        <script src="img/jquery.js"></script>
        <script src="img/tizen-web-ui-fw-libs.js"></script>
        <script src="img/tizen-web-ui-fw.js"
            data-framework-theme="tizen-white"></script>
        <script type="text/javascript" src="img/storage.js"></script>
        <script type="text/javascript" src="img/main.js"></script>
        <link rel="stylesheet" type="text/css" href="./css/style.css"/>
    </head>
    
    <body>
        <div data-role="page">
            <div data-role="header" data-position="fixed">
                <h1>NoteApp</h1>
            </div><!-- /header -->
    
            <div data-role="content">
          <textarea id="textbox"></textarea>
          <a href="#" id="btnUndo" data-role="button" data-icon="refresh">Undo</a>  
            </div><!-- /content -->
    
            <div data-role="footer" data-position="fixed">
                <h4>Tizen Cookbook</h4>
            </div><!-- /footer -->
        </div><!-- /page -->
    </body>
    </html>
    
  4. 通过右键点击 项目资源管理器 视图,选择 新建 | 其他 | JavaScript | JavaScript 源文件 来添加一个名为 storage.js 的新 JavaScript 文件。

  5. 将以下 JavaScript 函数插入到 storage.js 中:

    function load() {
      var content = localStorage.getItem('note');
      if (null != content) {
        $('#textbox').val(content);
      }
      $('#btnUndo').hide();
    }
    
    function save() {
      var sContent = $('#textbox').val();
      var previousVersion = localStorage.getItem('note');
      if (sContent != previousVersion) {
        sessionStorage.setItem('undo', previousVersion);
        $('#btnUndo').show();
      }
      localStorage.setItem('note', sContent);
    }
    
    function undo() {
      var content = sessionStorage.getItem('undo');
      if (null != content) {
        $('#textbox').val(content);
        localStorage.setItem('note', content);
        $('#btnUndo').hide();
      }
    }
    
  6. 打开 main.js 并将以下代码附加到初始化函数中:

    load();
    $('#textbox').bind('input propertychange', function() {
      save();
    });
    $('#btnUndo').on( "click", function(event, ui) {
      undo();
    });
    
  7. 保存所有修改过的文件,构建应用程序并运行它。

它是如何工作的...

应用程序使用 localStorage 存储单个笔记的数据。在应用程序启动时,load() 函数从持久化网页存储中获取键为 note 的数据,并将其设置为 ID 为 textboxtextarea 内容。

每次用户更改 textarea 内容时,都会执行 save() 函数。它将文本的上一个版本保存在 sessionStorage 中,键名为 undo,当前版本则保存到 localStorage

当用户点击 撤销 按钮时,undo() 函数会加载 sessionStorage 中键为 undo 的值。该应用程序只支持一个先前的状态,因此 撤销 按钮只能点击一次。此按钮在应用启动时默认隐藏,仅在可以返回时显示。请看以下截图:

它是如何工作的...

使用网页存储保存笔记的 Tizen web 应用程序

创建 Web SQL 数据库

在本章之前,我们讨论了如何将数据存储在文本文件和网页存储中。现在是时候关注关系型数据库了。Tizen web 应用程序支持Web SQL 数据库。HTML5 中 Web SQL 数据库 API 的底层实现依赖于SQLite数据库。

SQLite 是用 C 语言编写的,其源代码属于公共领域。根据其开发者的说法,SQLite 可能是全球最流行的 SQL 数据库,因为它随大多数现代智能手机和网页浏览器一起提供,且它也被内置在 PHP 中。

需要提到的是,W3C 工作组已于 2010 年停止了 Web SQL 数据库 API 的开发,因为所有相关方都在使用 SQLite 以及该 API 的底层引擎。从那时起,W3C 工作组转而专注于替代 API 的标准化,如网页存储和 Indexed Database。在我看来,这不应该让你太担心,因为 Tizen 支持 Web SQL 数据库 API,而且事实上,它非常方便。

准备工作

Web SQL 数据库 API 支持异步和同步操作。请注意,本食谱中的所有示例以及随后的两个食谱均与相同的 API 相关,并且仅包含异步操作。

操作步骤...

以下代码片段建立了与数据库 simpleTextEditor 的连接:

var db = null;
var dbVersion = 1.0;
var dbName = "simpleTextEditor";
var dbDesc = "Database for a simple text editor";
var dbSize = 1024 * 1024; //1MB
try {
  db = openDatabase(dbName, dbVersion, dbDesc, dbSize);
}
catch(err) {
  console.log(err.message);
}

注意

应使用函数openDatabaseSync()同步地创建一个新数据库或打开一个现有的数据库。它需要与openDatabase()相同的参数。

它是如何工作的...

上面的代码片段尝试使用函数openDatabase()异步打开一个数据库。如果数据库不存在,函数会尝试创建它。openDatabase()的必需参数包括名称、版本、完整显示名称(描述)以及估算的数据库大小(字节)。版本可以传递一个空字符串,若如此,数据库将会被打开,不管它的版本是什么。

可以指定一个回调函数作为可选的最后一个参数。如果数据库成功打开,将调用该函数。在前面的示例中,已经实现了一个匿名函数,它将消息记录到控制台。

如果发生错误,例如数据库版本不匹配或安全问题,可能会抛出异常。

另见

  • 请在接下来的两个示例中查找如何执行 SQL 语句以及如何处理通过 Web SQL 数据库 API 检索到的数据的教程和示例。如果您对 W3C 规范的更多信息感兴趣,请访问www.w3.org/TR/webdatabase/

在 Web SQL 数据库中执行查询

与任何数据库相关的最重要操作之一就是执行 SQL 查询。最常用的 SQL 语句有CREATE TABLEINSERTUPDATESELECT。当然,Web SQL 数据库背后的引擎 SQLite 支持多种其他 SQL 语句。在 Tizen Web 应用程序中应该能够使用它们中的每一个。关于每个语句的完整列表和语法细节可以在sqlite.org/lang.html的文档中找到。

本食谱解释了如何在 HTML5 中使用 Web SQL 数据库 API 执行 SQL 查询。

如何做到...

以下示例展示了如何执行 SQL 语句来创建一个新表以及如何插入数据:

  1. 使用以下示例中的源代码来执行单个 SQL 语句:

    function createTable() {
      db.transaction(function (transaction) {
        transaction.executeSql("CREATE TABLE IF NOT EXISTS tizenSimpleTextEditor (id INTEGER PRIMARY KEY, content TEXT)");
      });
    }
    
  2. 使用以下源代码执行一系列动态传递值的 SQL 语句:

    function insertData() {
      db.transaction(function (transaction) {
        transaction.executeSql("INSERT INTO tizenSimpleTextEditor(id, content) VALUES (?, ?)", [1, 'foo']);
        transaction.executeSql("INSERT INTO tizenSimpleTextEditor(id, content) VALUES (?, ?)", [2,   'bar']);
      });
    }
    

它是如何工作的...

查询可以使用数据库对象及其函数transaction()readTransaction()changeVersion()来执行。它们都会调用一个回调函数,在该函数中通过executeSql()来执行数据库操作。该函数最多接受四个参数,但第一个参数(SQL 语句)是必须的。可选参数包括一个包含 SQL 语句值的数组、一个用于处理查询结果的回调函数和一个用于处理错误的回调函数。

注意 SQL 语句中的问号,例如下面的示例:

transaction.executeSql("INSERT INTO tizenSimpleTextEditor(id, content) VALUES (?, ?)", [1, 'foo']);

它们将自动被替换为作为数组传入的值。每个值中的特殊符号也将被自动转义。这是一种方便且安全的方法,可以防止 SQL 错误和注入攻击。

在发生数据库错误时会抛出异常,这意味着之前示例中的createTable()insertData()函数必须在 try-catch 块中调用。

另请参阅

  • 关于如何创建一个创建 Web SQL 数据库 API 的应用程序以及如何执行 SQL 查询的说明将包含在下一个配方中。

从 Web SQL 数据库中检索数据

让我们开发一个应用程序,将上一个配方中与 Web SQL 数据库 API 相关的所有内容结合起来,并进一步演示如何检索数据。

该应用程序基于之前配方中探讨的简单文本编辑器。它有相同的用户界面,但与读取和写入文件不同,它的后端使用 Web SQL 数据库。

如何操作……

按照此教程创建一个由 Web SQL 数据库驱动的 Tizen Web 应用程序:

  1. 启动 Tizen IDE 并开始一个新的 Tizen Web 项目。

  2. 从用于创建新项目的向导中,选择Tizen Web UI 框架单页应用程序

  3. 更新index.html的内容,以匹配以下代码:

    <!DOCTYPE html>
    <html>
    
    <head>
      <meta charset="utf-8"/>
      <meta name="description" content="Simple text editor for Tizen powered by Web SQL database."/>
      <meta name="viewport" content="width=device-width,user-scalable=no"/>
    
      <link rel="stylesheet" href="tizen-web-ui-fw/latest/themes/tizen-white/tizen-web-ui-fw-theme.css" name="tizen-theme"/>
      <title>Web SQL Database Demo</title>
      <script src="img/jquery.js"></script>
      <script src="img/tizen-web-ui-fw-libs.js"></script>
      <script src="img/tizen-web-ui-fw.js"
     data-framework-theme="tizen-white"></script>
      <script type="text/javascript" src="img/db.js"></script>
      <script type="text/javascript" src="img/main.js"></script>
      <link rel="stylesheet" type="text/css" href="./css/style.css"/>
    </head>
    
    <body>
      <div data-role="page">
        <div data-role="header" data-position="fixed">
          <h1>Web SQL Database Demo</h1>
        </div><!-- /header -->
    
        <div data-role="content">
          <a href="#" id="btnSave" data-role="button" data-icon="check">Save</a>  
          <textarea id="textbox"></textarea>  
        </div><!-- /content -->
    
        <div data-role="footer" data-position="fixed">
          <h4>Tizen Cookbook</h4>
        </div><!-- /footer -->
      </div><!-- /page -->
    </body>
    </html>
    
  4. 转到项目资源管理器视图,选择项目,然后右键单击它以打开上下文菜单。导航到新建 | 其他 | JavaScript | JavaScript 源文件,向项目添加一个新的文件db.js

  5. 之后,打开文件db.js并插入以下 JavaScript 代码:

    var db = null;
    var dbTable = 'tizenSimpleTextEditor';
    
    function openDb() {
      var dbVersion = 1.0;
      var dbName = "simpleTextEditor";
      var dbDesc = "Database for a simple text editor";
      var dbSize = 1024 * 1024; //1MB
      db = openDatabase(dbName, dbVersion, dbDesc, dbSize);
    }
    
    function retrieveData() {
      db.transaction(function (transaction) {
        transaction.executeSql("CREATE TABLE IF NOT EXISTS "+dbTable+" (id INTEGER PRIMARY KEY, content TEXT)");
        transaction.executeSql("SELECT content FROM "+dbTable+" WHERE id = ?", [1],
        function (sqlTransaction, sqlResult) {
          if (0 < sqlResult.rows.length) {
            $('#textbox').val(sqlResult.rows.item(0).content);
          }
        });
      });
    }
    

    load()save()函数的实现也应放在同一文件中,如下所示:

    function load() {
      try {
        openDb();
        retrieveData();
      }
      catch(err) {
        alert('Unable to load data!');
        console.log('Unable to load data: '+err.message);
      }
    }
    
    function save() {
      try {
        if (null == db) {
          throw {message:"Database has not been opened."};
        }
    
        db.transaction(function (transaction) {
          var sTxt = $('#textbox').val();
          transaction.executeSql("REPLACE INTO "+dbTable+"(id, content) VALUES (?, ?)", [1, sTxt]);
        });
      }
      catch(err) {
        alert('Unable to save data!');
        console.log('Unable to save data: '+err.message);
      }
    }
    
  6. 将以下源代码插入到文件main.js中的初始化函数中:

    load();
    
    $('#btnSave').bind( "click", function(event, ui) {
      save();
    });
    
  7. 保存所有更改,构建应用程序,并在 Tizen 模拟器或设备上运行它。

它是如何工作的……

该应用程序与配方创建一个简单文本编辑器中开发的应用程序具有完全相同的用户界面和用户体验。唯一的区别是文本是加载并保存在 Web SQL 数据库的tizenSimpleTextEditor表中的simpleTextEditor

数据库表有两列:idcontentid列的类型是INT,并且是主键。另一个列的类型是TEXT。请注意,SQLite 中所有数据类型的完整列表可见于www.sqlite.org/datatype3.html

load()函数在应用程序启动后由文件main.js中的初始化函数立即调用。它通过执行openDb()retrieveData()函数来尝试打开数据库并检索保存的文本值。如果数据库不存在,将由openDb()函数创建。

函数 retrieveData() 创建一个名为 tizenSimpleTextEditor 的表(如果该表不存在),通过执行 SELECT 语句来检索数据,并在以下的匿名回调函数中处理其结果:

function (sqlTransaction, sqlResult) {
  if (0 < sqlResult.rows.length) {
    $('#textbox').val(sqlResult.rows.item(0).content);
  }
}

变量 sqlResult 是一个对象,其中包含有关最后插入行的信息(如果有)在属性 insertId 中,受影响的行数在属性 rowsAffected 中,以及所有返回行的 rows 数组。在此案例中,没有插入或受影响的行,因为执行的是 SQL SELECT 语句。表 tizenSimpleTextEditor 的结构只允许返回一行或没有行。如果结果包含一行,则其属性 content 的值将在 ID 为 textbox 的 HTML5 textarea 中显示。在其他可能返回多行的情况中,应该使用循环遍历返回的数组。

函数 save() 执行一个事务,执行 SQL REPLACE 查询,将 textbox 的值存储到数据库表 simpleTextEditor 中,ID 为 1。请注意,这个表只有一行,因为这是一个示例应用程序。在实际应用中,只有在表中有大量记录时,才应该使用数据库。

另见

  • 请参考 SQLite 文档,了解支持的 SQL 命令的语法:sqlite.org/docs.html

  • 有关 Web SQL 数据库 API 的详细信息,可以在 W3C 工作组于 2010 年 11 月 18 日发布的最新版本标准文档中找到:www.w3.org/TR/webdatabase/

使用 IndexedDB

本章的最后一个配方专门介绍了 IndexedDB。这些数据库在 JavaScript 中自然集成,其规范由 W3C 标准化。这意味着 IndexedDB 的源代码将在支持 HTML5 的其他网页浏览器和平台上运行。

如何实现...

以下代码片段展示了如何使用 JavaScript 在索引数据库中存储和操作 2014 年 FIFA 世界杯的最佳射手数据:

  1. 创建并打开一个数据库:

    window.indexedDB = window.indexedDB || window.webkitIndexedDB;
    
    window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;
    window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange;
    
    var db;
    var request = window.indexedDB.open("FIFA2014", 1);
    
    request.onerror = function(event) {
      console.log("error");
    };
    
    request.onsuccess = function(event) {
      db = request.result;
    };
    
  2. 向数据库中插入初始数据:

    request.onupgradeneeded = function(event) {
      var db = event.target.result;
      var objectStore = db.createObjectStore("goalscorers", {keyPath: "id"});
      objectStore.add({id: "1", name: "James Rodriguez", country: "Columbia", goals: 6});
      objectStore.add({id: "2", name: "Thomas Muller", country: "Germany", goals: 5});
    }
    

    创建一个向数据库中插入对象的函数:

    function addGoalscorer(nId, sName, sCountry, nGoals) {
      var req = db.transaction(["goalscorers"], "readwrite").objectStore("goalscorers").add({ id: nId, name: sName, country: sCountry, score: nGoals});
      req.onsuccess = function(event) {
        console.log("Goalscorer added.");
      };
    
      req.onerror = function(event) {
        alert("Unable to add a goalscorer.");
      }
    }
    

    创建一个从数据库中删除对象的函数:

    function removeGoalscorer(key) {
      var req = db.transaction(["goalscorers"], "readwrite").objectStore("goalscorers").delete(key);
    
      req.onsuccess = function(event) {
        console.log("The selected goalscorer has been removed.");
      };
    
      req.onerror = function(event){
        console.log("Unable to remove the selected goalscorer.");
      };
    }
    
  3. 创建一个读取存储在索引数据库中的所有对象的函数:

    function readGoalscorers() {
    
    
      var objectStore = db.transaction("goalscorers").objectStore("goalscorers");
    
      objectStore.openCursor().onsuccess = function(event) {
        var cursor = event.target.result;
        if (cursor) {
          console.log("id:" + cursor.key + " Name: " + cursor.value.name + "(" + cursor.value.country + "), goals: " + cursor.value.goals);
          cursor.continue();
        }
      };
    }
    

它是如何工作的...

IndexedDB 存储对象。本配方中的代码片段插入、删除并读取代表 2014 年 FIFA 世界杯最佳射手的对象。

数据通过 JavaScript 对象db进行操作。使用window.indexedDB.open()打开数据库。如果数据库不存在,函数将在打开之前创建它。第一个参数是数据库的名称。第二个参数是可选的。如果提供,它必须是一个与数据库版本匹配的整数值。例如,在第一步的代码片段中,数据库版本设置为1

如果创建或更新数据库,将触发onupgradeneeded事件。根据第二步实现的代码片段,数据库创建后,将立即插入前两名顶级进球者。

函数addGoalscorer()removeGoalScorer()readwrite模式下执行事务,以修改存储的数据。函数readGoalscorers()中的事务模式没有显式指定,默认值readonly被赋给它。此函数仅检索数据,不对数据库进行任何修改,因此默认模式对它来说足够了。

本食谱中的代码片段将在控制台中打印所有检索到的数据以及可能发生的错误。请注意,这是一个简单的示例,用于演示 IndexedDB 的使用。在实际应用中,这些源代码应与 GUI 集成。

还需注意,最后三步中实现的任何函数必须在db对象成功初始化后执行。

另见

第五章:创建多媒体应用

本章将介绍以下食谱:

  • 播放本地音频文件

  • 播放本地视频文件

  • 在外部播放器中启动视频

  • 拍照

  • 生成线性条形码

  • 扫描线性条形码

  • 生成二维码

  • 扫描二维码

介绍

多媒体功能始终是智能设备中最重要且最容易区分的特点之一。无论 Tizen 设备的外形或用途如何,只要具备图形用户界面,它就能够运行多媒体应用程序。

本章将介绍最常见的多媒体任务:播放音频和视频文件、在线视频流、使用摄像头和处理条形码。

播放本地音频文件

几年前,在不同浏览器和平台上播放声音或视频是一个真正的挑战。如今,HTML5 为我们提供了播放音频和视频文件的标准方式,让开发者的生活变得更加轻松。

本章的第一个食谱将开发一个仅使用 HTML5 播放音频文件的 Tizen Web 应用程序。

准备工作

在开始之前,确保 Tizen 设备和模拟器上存在 MP3 文件。使用sdb push命令将 MP3 文件从开发计算机传输到 Tizen 设备或模拟器,例如:

sdb push happy.mp3 /opt/usr/media/Sounds/

如何做…

执行以下步骤,创建一个 Tizen Web 应用程序,播放已复制到 Tizen 设备或模拟器的文件:

  1. 启动 Tizen IDE 并创建 Tizen Web 项目。

  2. 从向导中选择Tizen Web UI Framework,然后选择单页面应用程序以创建项目。

  3. index.html的内容替换为以下源代码:

    <!DOCTYPE html>  
    <html>
    
    <head>
        <meta charset="utf-8"/>
        <meta name="description" content="Simple audio player for Tizen"/>
        <meta name="viewport" content="width=device-width,user-scalable=no"/>
    
        <link rel="stylesheet" href="tizen-web-ui-fw/latest/themes/tizen-white/tizen-web-ui-fw-theme.css" name="tizen-theme"/>
        <title>Simple Audio Player</title>
        <script src="img/jquery.js"></script>
        <script src="img/tizen-web-ui-fw-libs.js"></script>
        <script src="img/tizen-web-ui-fw.js"
            data-framework-theme="tizen-white"></script>
        <script type="text/javascript" src="img/main.js"></script>
        <link rel="stylesheet" type="text/css" href="./css/style.css"/>
    </head>
    
    <body>
        <div data-role="page">
            <div data-role="header" data-position="fixed">
                <h1>Simple Audio Player</h1>
            </div><!-- /header -->
    

    请注意,音频文件的 URI 应更改为与您的 Tizen 设备或模拟器上的声音文件匹配。

            <div data-role="content">
          <audio src="img/happy.mp3" controls autoplay></audio>
            </div><!-- /content -->
    
            <div data-role="footer" data-position="fixed">
                <h4>Tizen Cookbook</h4>
            </div><!-- /footer -->
        </div><!-- /page -->
    </body>
    </html>
    
  4. 保存所有更改。

  5. 构建应用程序后,在 Tizen 模拟器或设备上运行它。

工作原理

标准 W3C HTML5 audio元素负责播放 MP3 文件。根据 Tizen 文件系统规则设置 URI 作为src属性的值。controls属性添加了用于控制声音播放过程的按钮。最后的属性autoplay用于在启动应用程序时自动播放声音。

可与audio标签一起使用的其他可用属性包括loopmutedpreload。支持的音频格式包括 MP3、Ogg Vorbis 和 WAV。

工作原理

用于播放本地音频文件的 Tizen Web 应用程序

另请参阅

  • 关于标准 HTML5 音频元素的详细信息,请参阅www.w3.org/TR/html5/embedded-content-0.html#the-audio-element

  • 也可以从 Tizen Web 应用程序启动外部播放器来播放音频文件。查看在外部播放器中启动视频的示例,并尝试加载音频文件而不是视频文件。

播放本地视频文件

Tizen 提供了一个 API,用于从设备本地存储中检索多媒体文件。在此示例中,将创建一个使用 Content API 检索视频文件并使用 HTML5 video元素播放它们的应用程序。

Content API 负责发现诸如视频、音频文件、照片和其他图像等媒体文件。Tizen Web 应用程序支持以下视频格式:3GP、AVI、ASF、OGV、MP4、MKV 和 WMV。

准备工作

在开始之前,确保设备上有视频文件。最简单的方法是使用 SDB 及其push命令,将若干视频从计算机复制到 Tizen 设备或模拟器。

例如,以下命令将文件happy.mp4从计算机当前目录传输到附加的 Tizen 设备或模拟器的目录/opt/usr/media/Videos/

sdb push happy.mp4 /opt/usr/media/Videos/

请注意,使用 SDB 上传到设备的新视频可能不会出现在内容数据库中,除非重新启动设备或使用内容 API 创建它们。

如何操作...

执行以下步骤,创建一个 Tizen Web 应用程序来获取并播放视频文件:

  1. 启动 Tizen IDE。

  2. 使用Tizen Web UI Framework创建一个新的 Tizen Web 项目,目标是多页面应用程序

  3. 使用小部件配置编辑器打开 config.xml 文件并转到 权限 标签。点击 添加 按钮,选择 http://tizen.org/privilege/content.read 来使用此权限。

  4. index.html 的内容替换为以下源代码:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8"/>
        <meta name="description" content="Simple video player for Tizen"/>
        <meta name="viewport" content="width=device-width,user-scalable=no"/>
        <link rel="stylesheet" href="tizen-web-ui-fw/latest/themes/tizen-white/tizen-web-ui-fw-theme.css" name="tizen-theme"/>
        <title>Simple Video Player</title>
        <script src="img/jquery.js"></script>
        <script src="img/tizen-web-ui-fw-libs.js"></script>
        <script src="img/tizen-web-ui-fw.js"
            data-framework-theme="tizen-white"></script>
      <script type="text/javascript" src="img/videoManager.js"></script>
        <script type="text/javascript" src="img/main.js"></script>
        <link rel="stylesheet" type="text/css" href="./css/style.css"/>
    </head>
    <body>
    
  5. 接下来,请附加以下源代码来完成第一个页面:

        <div data-role="page" id="videoManager">
            <div data-role="header" data-position="fixed">
                <h1>Simple Video Player</h1>
            </div><!-- /header -->
            <div data-role="content">
                <h2>Videos</h2>
                <ul id="listVideos" data-role="listview"></ul>
            </div><!-- /content -->
            <div data-role="footer" data-position="fixed">
                <h4>Tizen Cookbook</h4>
            </div><!-- /footer -->
        </div><!-- /page one -->
    
  6. 在同一文件中插入第二个页面,如下所示:

        <div data-role="page" id="videoPlayer">
            <div data-role="header" data-position="fixed">
                <h1>Simple Video Player</h1>
            </div><!-- /header -->
            <div data-role="content">
                <h2>Video Player</h2>
                <video id="player" width="320" height="240" src="" controls></video>
                <p><a href="#videoManager" data-role="button">Back</a></p>
            </div><!-- /content -->
            <div data-role="footer" data-position="fixed">
                <h4>Tizen Cookbook</h4>
            </div><!-- /footer -->
        </div><!-- /page two -->
    </body>
    </html>
    
  7. js 目录中添加一个新的 JavaScript 文件 videoManager.js,并在其中放入以下源代码:

    function onError(response) {
      console.log( "Error: " + response.name);
    }
    
    function selectVideo(sContentURI) {
      $("#player").attr("src",sContentURI);
      $.mobile.changePage("#videoPlayer");
    }
    
    function bindClick(item, sContentURI) {
      item.bind("click", function(event) {
        selectVideo(sContentURI);
      });
    }
    
    function createListItem(sText) {
      return $('<li>').append($('<a/>', {
        'href': '#',
        'text': sText
      }));  
    }
    
    function mediaItems (media) {
      if (0 == media.length) {
        $('#listVideos').append(createListItem('No data'));
      }
      else {
        for(var nVideoIter in media) {
          var listItem = createListItem(media[nVideoIter].title);    
          bindClick(listItem, media[nVideoIter].contentURI);
          $('#listVideos').append(listItem);
        }
      }
      $('#listVideos').listview('refresh');
    }
    
    function loadVideos() {
      var filter = new tizen.AttributeFilter("type", "EXACTLY", "VIDEO");
      tizen.content.find(mediaItems, onError, null, filter);
    }
    
  8. 打开 main.js 文件,并将初始化函数中自动生成的硬件返回按钮处理代码替换为以下代码:

    loadVideos();
    
    var backEvent = function(e) {
      if ( e.keyName == "back" ) {
        unregister();
      }
    };
    
  9. 保存所有更改,构建并在 Tizen 模拟器或设备上运行应用程序。

工作原理

该应用程序包含两个页面。第一个页面显示所有存储在本地存储中的视频文件的列表。用户可以点击每个视频并转到第二个页面,在那里视频被加载并可以播放。如果没有找到视频,将在第一个页面显示消息 没有数据

loadVideos() 函数通过 Tizen 内容 API 中的 find() 函数来查找可用的视频文件。成功后,mediaItems() 函数创建一个列表并加载所有检索到的视频的标题。当点击列表中的某个项时,selectVideo() 函数将用户转到第二页并加载视频。

请注意,在本教程倒数第二步中硬件返回按钮的处理。每个 Tizen 移动设备上都应该有菜单和返回硬件按钮。需要使用字符串 backmenu 来识别哪个硬件按钮被点击。

另请参阅

在外部播放器中启动视频

在本教程中,您将学习另一种播放视频文件的方法。这次,视频不会在当前应用程序内播放,而是会加载到外部播放器中,外部播放器将通过 Tizen 应用程序 API 启动。

准备工作

与前面的示例一样,必须在用于测试的 Tizen 设备或模拟器上存在视频文件。确保文件存在,可以使用 SDB 复制视频文件。例如,以下命令将 happy.mp4 文件从计算机传输到目标 Tizen 设备:

sdb push happy.mp4 /opt/usr/media/Videos/

如何执行...

执行以下步骤以创建一个在外部应用程序中播放视频文件的应用程序:

  1. 启动 Tizen IDE 并创建一个新的 Tizen Web 项目。

  2. 从向导中创建新项目,选择 Tizen Web UI 框架,然后选择 单页面应用程序

  3. 使用小部件配置编辑器打开 config.xml 文件,转到 权限 标签。点击 添加 按钮,选择 http://tizen.org/privilege/application.launch 以使用此权限。

  4. 用以下源代码替换 index.html 的内容:

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8"/>
        <meta name="description" content="Play video file in external player"/>
        <meta name="viewport" content="width=device-width,user-scalable=no"/>
    
        <link rel="stylesheet" href="tizen-web-ui-fw/latest/themes/tizen-white/tizen-web-ui-fw-theme.css" name="tizen-theme"/>
        <title>Play Video in External Player</title>
        <script src="img/jquery.js"></script>
        <script src="img/tizen-web-ui-fw-libs.js"></script>
        <script src="img/tizen-web-ui-fw.js"
            data-framework-theme="tizen-white"></script>
      <script type="text/javascript" src="img/videoManager.js"></script>
        <script type="text/javascript" src="img/main.js"></script>
        <link rel="stylesheet" type="text/css" href="./css/style.css"/>
    </head>
    
    <body>
        <div data-role="page">
            <div data-role="header" data-position="fixed">
                <h1>Launch External Video Player</h1>
            </div><!-- /header -->
    
            <div data-role="content">
          <a href="#" id="btnPlay" data-role="button">Play Video</a>
            </div><!-- /content -->
    
            <div data-role="footer" data-position="fixed">
                <h4>Tizen Cookbook</h4>
            </div><!-- /footer -->
        </div><!-- /page -->
    </body>
    </html>
    
  5. 右键点击 项目资源管理器,选择 新建,然后选择 其他,接着选择 JavaScript,然后选择 JavaScript 源文件,以添加名为 videoManager.js 的新 JavaScript 文件。

  6. 将以下 JavaScript 函数插入到 videoManager.js 文件中:

    function onSuccess() {
    }
    
    function onError(err) {
      console.log("Error: " + err.name);
    }
    
    function launchVideoPlayer() {
      var appControl = new tizen.ApplicationControl("http://tizen.org/appcontrol/operation/view", "file:///opt/usr/media/Videos/happy.mp4");
      tizen.application.launchAppControl(appControl, null, onSuccess, onError);
    }
    
  7. 将以下源代码附加到 main.js 文件的初始化函数中:

    $('#btnPlay').on( "click", function(event, ui) {
      launchVideoPlayer();
    });
    
  8. 保存所有更改。构建应用程序,然后在 Tizen 模拟器或设备上启动该应用程序。

它是如何工作的

上面的示例使用了应用程序 API。launchVideoPlayer() 函数启动外部应用程序以播放由 URI 指定的视频文件。请注意,文件名应与设备或模拟器上存在的视频文件名称匹配。

还有更多...

本示例中的操作使用 http://tizen.org/appcontrol/operation/view 操作 ID 打开视频播放器。操作 ID 的其他可用选项如下:

  • http://tizen.org/appcontrol/operation/call 操作拨打指定号码的电话,使用 tel 方案

  • http://tizen.org/appcontrol/operation/dial 操作启动拨号盘,并输入由 tel 方案指定的电话号码

  • http://tizen.org/appcontrol/operation/create_content 操作创建内容,如照片

  • http://tizen.org/appcontrol/operation/compose 操作用于编写信息,例如短信或电子邮件

  • http://tizen.org/appcontrol/operation/pick 显示项目列表,并返回用户选择的项目

  • http://tizen.org/appcontrol/operation/share 操作将数据与其他应用程序共享

  • http://tizen.org/appcontrol/operation/multi_share 操作将多个项目与其他应用程序共享

另见

拍照

所有现代移动设备都配备了高质量的摄像头,具有出色的视频录制和拍照能力。在本教程中,您将学习如何创建一个 Tizen Web 应用程序,用于利用设备摄像头捕获和显示图像。

如何操作……

执行以下步骤来创建一个新项目,并构建一个能够拍摄照片的 Tizen Web 应用程序:

  1. 启动 Tizen IDE,并创建一个使用 Tizen Web UI 框架的新 Tizen Web 项目,用于 单页面应用程序

  2. 使用 Widget 配置编辑器打开 config.xml 文件,选择 权限 选项卡。点击 添加 按钮,并插入 http://tizen.org/privilege/content.read 权限。

  3. 通过替换以下 HTML5 来编辑 index.html

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8"/>
      <meta name="description" content="Simple Tizen web application for taking photos."/>
      <meta name="viewport" content="width=device-width,user-scalable=no"/>
    
      <link rel="stylesheet" href="tizen-web-ui-fw/latest/themes/tizen-white/tizen-web-ui-fw-theme.css" name="tizen-theme"/>
      <title>Photographer</title>
      <script src="img/jquery.js"></script>
      <script src="img/tizen-web-ui-fw-libs.js"></script>
      <script src="img/tizen-web-ui-fw.js" data-framework-theme="tizen-white"></script>
      <script type="text/javascript" src="img/photographer.js"></script>
      <script type="text/javascript" src="img/main.js"></script>
      <link rel="stylesheet" type="text/css" href="./css/style.css"/>
    </head>
    
    <body>
    

    以下 HTML 创建一个单页面,其中包含一个用于捕获照片的元素和一个用于显示照片的图像占位符:

      <div data-role="page">
        <div data-role="header" data-position="fixed">
        <h1>Photographer</h1>
      </div><!-- /header -->
    
      <div data-role="content">
          <p><label id="labelPhoto" for="photo">Take a photo</label>
          <input id="photo" type="file" accept="image/*" capture="camera" name="file" style="display:none;">
          </p>
          <p><img id="photoFrame" src="img/" width="200" /></p>
      </div><!-- /content -->
    
      <div data-role="footer" data-position="fixed">
        <h4>Footer content</h4>
        </div><!-- /footer -->
      </div><!-- /page -->
    </body>
    </html>
    
  4. 转到 项目资源管理器,点击鼠标右键,选择 新建,然后 其他,然后 JavaScript,接着选择 JavaScript 源文件。创建一个名为 photographer.js 的新文件。

  5. 将以下 JavaScript 源代码插入到 photographer.js 文件中:

    function onError(response) {
      console.log( "Error: " + response.name);
    }
    
    function loadImage(media) {
      if (0 < media.length) {
        $("#photoFrame").attr("src",media[0].contentURI);
        $('#photoFrame').show();
      }
    }
    
    function findImages() {
      var filterBy = new tizen.AttributeFilter("type", "EXACTLY", "IMAGE");
      var orderBy = new tizen.SortMode("modifiedDate", "DESC");
      tizen.content.find(loadImage, onError, null, filterBy,orderBy);
    }
    Modify main.js by inserting the source code below into the initialization function:
    $('#photoFrame').hide();
    
    $('#photo').change(function() {
      console.log( "images saved." );
      findImages();
    });
    
  6. 将所有文件保存、构建,并在 Tizen 模拟器或设备上运行应用程序。

注意

如果在开发计算机上有可用的网络摄像头,Tizen 模拟器将尝试使用它来捕获图像。

工作原理

当用户点击 拍照 标签时,摄像头将被激活。之后,如果用户决定点击返回按钮而不拍照,则不会发生任何事情,但如果拍摄了照片,则隐藏输入字段的内容将被更改,并触发 findImages() 函数。该函数的目的是检索所有图片,并按修改日期降序排序。在提供的结果集中,第一张图片是用户拍摄的最新照片。loadImage() 函数处理结果,并在具有 photoFrame ID 的 HTML5 图像元素中加载这些图像。

photographer.js 文件中的 JavaScript 使用 Tizen Content API 获取最新图片,必须设置权限 content.read,否则会抛出 WebAPIException 错误,类型为 SecurityError

还有更多内容……

可以通过类似的方式在 Tizen Web 应用程序中录制视频和音频文件。HTML5 输入元素的属性 accept 应设置为 video/* 以录制视频。要捕获声音,其值应设置为 audio/*

<input> 标签中属性 capture 的值应与以下选项之一匹配:cameracamcordermicrophonefilesystem。请注意,其默认值为 filesystem,在此模式下,用户将被要求从本地存储中选择文件。

另请参阅

  • 探索随 Tizen SDK 提供的 SelfCamera 示例应用程序,了解如何创建能够显示前置摄像头视频流并捕获照片的更高级别 Web 应用程序。

生成线性条形码

本章的其余食谱都专注于条形码。有两大类条形码,分别是:

  • 一维1D)条形码,仅包含相同高度、不同宽度的条形线。常见的一维条形码类型有 Code 39、Code 128、Code 25 Interleaved 2 of 5、UPS、EAN-8 和 EAN-13。

  • 二维2D)条形码,根据其类型可能包含不同的几何图形和模式。最常见的 2D 条形码类型有 QR Code、DataMatrix 和 Aztec Code。

条形码的生成和扫描是复杂且具体的操作,具体取决于条形码的类型。推荐且最简单的实现方式是使用经过验证的第三方开源库。

在本食谱中,你将学习如何在 Tizen Web 应用程序中使用 JavaScript 生成一维 Code 39 和 Code 25 Interleaved 2 of 5 条形码。将使用开源项目 jquery-barcode,因为它可以轻松集成到使用 Tizen UI 框架(基于 jQuery Mobile 和 jQuery)创建的应用程序中。该项目采用 MIT 许可协议,并可以从code.google.com/p/jquery-barcode/下载。

如何操作...

执行以下步骤,创建一个能够生成线性条形码的 Tizen Web 应用程序:

  1. 启动 Tizen IDE,使用Tizen Web UI Framework创建一个新的 Tizen Web 项目,用于单页应用程序

  2. 将以下 CSS 类附加到styles.css文件中,该文件位于css目录下:

    .barcodeImg {
      display: none;
      width:200px;
      height:50px;
      border:1px solid #003366;
    }
    
  3. 下载jquery-barcode库并将其保存到js目录。

  4. index.html的内容替换为以下源代码:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8"/>
        <meta name="description" content="Generate one-dimensional Code 39 and Code 25 Interleaved 2of 5 barcodes"/>
        <meta name="viewport" content="width=device-width,user-scalable=no"/>
    
        <link rel="stylesheet" href="tizen-web-ui-fw/latest/themes/tizen-white/tizen-web-ui-fw-theme.css" name="tizen-theme"/>
        <title>Linear Barcode Generator</title>
        <script src="img/jquery.js"></script>
        <script src="img/tizen-web-ui-fw-libs.js"></script>
        <script src="img/tizen-web-ui-fw.js"
            data-framework-theme="tizen-white"></script>
      <script src="img/jquery.barcode.0.3.js"></script>   
        <script type="text/javascript" src="img/main.js"></script>
        <link rel="stylesheet" type="text/css" href="./css/style.css"/>
    </head>
    <body>
        <div data-role="page">
            <div data-role="header" data-position="fixed">
                <h1>Linear Barcode Generator</h1>
            </div><!-- /header -->
            <div data-role="content">
        <a href="#" id="btnCode39" data-role="button" data-icon="check">Code39</a>  
        <div id="barcode39" class="barcodeImg">1234</div>
        <br />
        <a href="#" id="btnI25" data-role="button" data-icon="check">Code 25 Interleaved 2of 5</a>  
        <div id="barcodeI25" class="barcodeImg">1234</div>
            </div><!-- /content -->
            <div data-role="footer" data-position="fixed">
                <h4>Tizen Cookbook</h4>
            </div><!-- /footer -->
        </div><!-- /page -->
    </body>
    </html>
    Insert the source code below into to initialization function at main.js:
    $('#btnCode39').bind( "click", function(event, ui) {
      $('#barcode39').barcode({code:'code39'});
      $('#barcode39').show();
      $('#btnCode39').hide();
    });
    
    $('#btnI25').bind( "click", function(event, ui) {
      $('#barcodeI25').barcode({code:'I25'});
      $('#barcodeI25').show();
      $('#btnI25').hide();
    });
    
  5. 保存所有更改并在 Tizen 模拟器或设备上运行应用程序。

工作原理

该应用程序包含两个按钮。点击按钮后会生成条形码,且点击的按钮会消失。条形码的高度、宽度和边框在barcodeImg CSS 类中进行设置。

jquery-barcode 库获取元素的 HTML 内容,基于此内容生成条形码,并将其替换为生成的条形码图像。此示例应用程序中的两个按钮会根据1234的输入数据生成条形码。在实际应用中,建议在条形码生成时显示加载标签。

还有更多……

另一个用于生成 Code 39 条形码的有用开源 JavaScript 库名为barcode-39.js。该库采用 MIT 许可协议,由 Erik Zettersten 开发。源代码可在 GitHub 上找到,网址为github.com/erik5388/barcode-39.js

另见

  • 查看下一个食谱,了解如何读取线性条形码并从中获取数据

扫描线性条形码

本配方将展示如何在 Tizen Web 应用程序中读取线性 Code 39 条形码。此时,GitHub 上最流行的开源 JavaScript 库 BarcodeReader 将被使用。它由 Eddie Larsson 开发,支持识别 Code 39、Code 128、Code 93 和 EAN-13 条形码。

准备工作

在项目的根目录中插入一个适当的条形码图像。例如,可以使用前一个配方中的示例生成图像。

从 GitHub 下载 BarcodeReader 并将其文件插入到项目的 js 目录中。有关 BarcodeReader 的更多信息,请参考 github.com/EddieLa/BarcodeReader

如何做...

执行以下三个简单步骤,在 Tizen Web 应用程序中基于 BarcodeReader 实现线性条形码扫描功能,该应用程序使用 Tizen Web UI 框架:

  1. 插入一个条形码图像的 HTML(例如,名为 code39``.``png)以及一个段落和一个按钮,如以下代码所示:

    <img id="imgBarcode" src="img/code39.png">
    <p id="labelResult"></p>
    <a href="#" id="btnScan" data-role="button">Scan</a>
    
  2. 在应用程序的 initialization 函数之前放置以下代码:

    barcodeScanner = new Worker("js/DecoderWorker.js");
    barcodeScanner.onmessage = function(e) {
      if (false == e.data.success) {
        $('#labelResult').html("Error");
        return;
      }
      var tempArray = e.data.result;
      for (var nIter = 0; nIter < tempArray.length; nIter++) {
        if(-1 == resultArray.indexOf(tempArray[nIter])) {
          console.log(tempArray[nIter]);
          resultArray.push(tempArray[nIter]);
        }
      }
      $('#labelResult').html(resultArray.join("<br />"));
    };
    
    function scanBarcode() {
      $('#labelResult').html('Please wait...');
      ctx.drawImage(document.querySelector('#imgBarcode'),0,0,Canvas.width,Canvas.height);
      resultArray = [];
      barcodeScanner.postMessage({pixels: ctx.getImageData(0,0,Canvas.width,Canvas.height).data, width: Canvas.width, height: Canvas.height, cmd: "normal"});
    }
    
  3. 将以下源代码附加到初始化函数中:

    Canvas = document.createElement("canvas");
    Canvas.width=320;
    Canvas.height=240;
    ctx = Canvas.getContext("2d");
    var resultArray = [];
    
    $('#btnScan').bind( "click", function(event, ui) {
      scanBarcode();
    });
    

它是如何工作的

当用户点击 ID 为 btnScan 的按钮时,条形码会从 ID 为 imgBarcode 的图像中读取。图像处理由 scanBarcode 函数启动,工作结果由 JavaScript 对象 barcodeScannerBarcodeReader 库完成。Web Worker 用于在后台运行脚本 js/DecoderWorker.js,而不会影响应用程序的整体性能。最终结果显示在 HTML 中 ID 为 labelResultp 标签中。如果条形码无法识别,labelResult 显示的值将为 错误

它是如何工作的

一个用于扫描线性条形码的示例 Tizen Web 应用程序

另见

  • 如需更多详细信息,请探索应用程序的源代码,它与本书的其他示例应用程序一起提供。

生成 QR 代码

快速响应 (QR) 是当今最流行的条形码类型,属于 2D 条形码。

QR 代码由日本公司 DENSO 发明,DENSO 是丰田集团的一部分。它们最初用于汽车制造中的零件追踪。由于该格式在存储数据方面的优异能力,QR 代码迅速扩展到其他行业。随着高分辨率相机智能手机的崛起,QR 代码的流行度进一步增加。

在下一个配方中,我们将讨论在 Tizen Web 应用程序中使用第三方开源 JavaScript 库生成 QR 代码。

准备工作

本配方将使用一个第三方开源 JavaScript 库,它是项目 qrcode-generator 的一部分。源代码可以在 GitHub 上获取。

qrcode.js 文件添加到 Tizen Web 应用项目的 js 目录中。该文件可以在 github.com/kazuhikoarase/qrcode-generator/tree/master/js 获取。

如何操作...

执行以下步骤,在您的 Tizen Web 应用中使用 JavaScript 生成二维码:

  1. 在 HTML 文件的头部包含 JavaScript 文件,如以下代码所示:

    <script type="text/javascript" src="img/qrcode.js"></script>
    
  2. 使用 HTML 创建用户界面:

    <label for="basic">Text:</label>
    <input type="text" name="name" id="inputText" value=""  />
    <a href="#" id="btnGenerateQR" data-role="button">Generate QR Code</a>
    <div id="barcode"></div>
    
  3. 实现一个 JavaScript 函数,根据用户输入的文本生成二维码:

    function generateQrCode() {
      var sInput = $('#inputText').val().replace(/^[\s\u3000]+|[\s\u3000]+$/g, '');
      try {
        var barcodeQR = qrcode(4, 'M');
        barcodeQR.addData(sInput);
        barcodeQR.make();
        $('#barcode').html(barcodeQR.createImgTag(8));
      }
      catch (err){
        $('#barcode').html(err.name + ": " + err.message);
      }
    }
    
  4. 创建一个按钮处理程序来执行 JavaScript 函数。建议将此代码放在 main.js 的初始化函数中:

    $('#btnGenerateQR').bind( "click", function(event, ui) {
      generateQrCode();
    });
    

工作原理

generateQrCode() 函数从 inputText 获取用户输入,生成二维码,并将其放置在具有 barcode ID 的 div 中。请注意,已使用正则表达式去除无效字符。根据第三方库的文档,二维码的类型可能在 1 到 10 之间变化。遮罩模式和 BCH 码(循环冗余检查类)取决于指定的类型。允许的错误校正级别值包括:

  • 低 (L):最多可恢复 7% 的编码数据

  • 中等 (M):最多可恢复 15% 的编码数据

  • 四分位 (Q):最多可恢复 25% 的编码数据

  • 高 (H):最多可恢复 30% 的编码数据

错误校正级别的目的是定义应添加到条形码中的备份数据量。前一个示例使用了中等错误校正。

条形码图像使用 createImgTag() 函数创建并显示。可选地,可以将单元格大小和边距作为参数传入。默认单元格大小为 2,默认边距为 4 倍。

工作原理

展示二维码生成的 Tizen Web 应用程序

还有更多...

编码为二维码的数据格式取决于其目的。前面的示例仅编码纯文本。如果您想序列化一个网站,应该添加前缀 URL。如果要将电话号码存储在条形码中,请添加前缀 TEL。如果要创建一个存储联系信息的二维码,强烈建议遵循 vcard 格式。

另请参见

  • 本书提供了一个基于前述教程的 Tizen Web 应用程序示例,供您参考。如果在实现过程中遇到任何问题,请使用该示例作为参考。

扫描二维码

ZXing(发音为 Zebra Crossing)因其在 Android 应用中的广泛使用,已成为扫描条形码的事实标准。它是用 Java 创建的,并已移植到其他多个语言和平台。Lazar Laszlo 发布的 ZXing JavaScript 移植版本命名为 jsqrcode,并在 GitHub 上公开。该项目和 JavaScript 移植的源代码都可在 Apache 许可证 2.0 下使用。

准备工作

获取 jsqrcode 的源代码,并将所有 JavaScript 文件复制到项目的 js 目录中。从 github.com/LazarSoft/jsqrcode 下载 jsqrcode

下一个示例解码图像中名为 qr``.``png 的二维码。确保该图像位于项目的根目录中,或者在图像的 HTML 属性 src 中设置其他位置。

如何操作...

执行以下步骤以在 Tizen Web 应用中集成二维码扫描功能:

  1. 按以下顺序包含 jsqrcode 的 JavaScript 文件:

    <script type="text/javascript" src="img/grid.js"></script>
    <script type="text/javascript" src="img/version.js"></script>
    <script type="text/javascript" src="img/detector.js"></script>
    <script type="text/javascript" src="img/formatinf.js"></script>
    <script type="text/javascript" src="img/errorlevel.js"></script>
    <script type="text/javascript" src="img/bitmat.js"></script>
    <script type="text/javascript" src="img/datablock.js"></script>
    <script type="text/javascript" src="img/bmparser.js"></script>
    <script type="text/javascript" src="img/datamask.js"></script>
    <script type="text/javascript" src="img/rsdecoder.js"></script>
    <script type="text/javascript" src="img/gf256poly.js"></script>
    <script type="text/javascript" src="img/gf256.js"></script>
    <script type="text/javascript" src="img/decoder.js"></script>
    <script type="text/javascript" src="img/qrcode.js"></script>
    <script type="text/javascript" src="img/findpat.js"></script>
    <script type="text/javascript" src="img/alignpat.js"></script>
    <script type="text/javascript" src="img/databr.js"></script>
    
  2. 使用 HTML 创建一个简单的用户界面,例如以下代码:

    <img id="imgBarcode" src="img/qr.png">
    <p id="labelResult"></p>
    <a href="#" id="btnScan" data-role="button">Scan</a>
    
  3. 在初始化函数中创建一个按钮处理程序。默认情况下,此函数位于 main.js 文件中:

    qrcode.callback = function(data) { $('#labelResult').html('Result: '+data); };
    
    $('#btnScan').bind( "click", function(event, ui) {
      var sImgSrc = $('#imgBarcode').attr("src");
      qrcode.decode(sImgSrc);
    });
    

注意

请注意,在编写本食谱时,最新版本的 jsqrcode 存在一些小的 JavaScript 错误。当构建书中提供的二维码扫描示例应用时,这些错误也会出现。尽管存在这些问题,仍然可以继续进行应用的打包和测试,因为这些错误不会影响二维码扫描。

它是如何工作的

使用 jsqrcode 扫描图像中的二维码非常简单。该教程的用户界面包含以下三个组件:

  • 加载将被扫描的条形码的图像

  • 一个显示从二维码读取的数据的标签

  • 启动扫描过程的按钮

一个用于处理读取数据的匿名函数作为回调函数设置到 JavaScript 对象 qrcode 中。调用该对象的 decode() 方法来扫描图像。条形码的文件路径和名称来自图像 ID 为 imgBarcodesrc 属性,并作为参数传递给 decode()

它是如何工作的

一个用于从图像中扫描二维码的 Tizen Web 应用

另见

  • 你可以通过将本食谱中的源代码与拍照功能结合,创建一个扫描来自相机捕获的二维码的 Tizen Web 应用

第六章:开发社交网络应用

在本章中,我们将涵盖以下内容:

  • 在 Tizen 中开发 Facebook 应用

  • 获取 Facebook 新闻源

  • 获取 Facebook 好友列表

  • 访问 Facebook 个人资料信息

  • 阅读 Facebook 消息

  • 获取 Facebook 通知

  • 更新 Facebook 状态

  • 从 Twitter 中筛选 Tizen 新闻源

  • 在 Tizen 中开发 LinkedIn 应用

  • 获取 LinkedIn 更新

介绍

在不到十年的时间里,社交网络已成为现代生活的重要组成部分。大多数人喜欢社交网络,尽管必须说也有一些人讨厌它们。如今,社交网络已经如此流行,无论你喜欢与否,迟早你都必须开发一个社交 Tizen 应用程序。

新的社交网络每天都在发展,但本章将仅关注最受欢迎的社交网络:Facebook、Twitter 和 LinkedIn。同时,虽然我们不会详细讨论,但值得一提的是开源社交引擎 pump.io,它为 Identi.ca 提供支持。

在开发 Tizen 应用程序时,请记住,不同地区主导的社交网络有所不同。很多具有区域性影响的社交网络,如 俄罗斯 VK (Вконтакте),都存在,并且对于面向特定国家/地区用户的应用程序,集成这些社交网络需要谨慎考虑。同时,也要注意一些社交网络在某些地区无法使用。例如,中国自 2008 年起 Facebook 无法使用,Twitter 也在一年后被封锁。

本章中的示例基于社交网络直接提供的公共 API。如果您对更简单的身份验证解决方案感兴趣,可以尝试使用第三方服务,例如 oauth.io/

在 Tizen 中开发 Facebook 应用

Facebook 提供了一个强大的 API,用于浏览和管理数据。授权基于 OAuth 2.0。开发者必须创建一个 Facebook 应用程序,并在用户同意授权后获得访问令牌,才能访问和使用他们的敏感信息。每个 API 功能都需要特定的权限;当用户开始使用应用程序时,必须授予应用程序相应的权限,否则 API 将无法正常工作。

在本教程中,您将学习如何创建一个 Facebook 应用程序,并使用 JavaScript 实现最简单的授权流程来获取访问令牌。

准备工作

Facebook 开发者门户要求您使用现有的 Facebook 用户凭证登录。没有注册社交网络账户,就无法开发 Facebook 应用程序。在继续之前,请确保您拥有一个 Facebook 账户。

如何操作...

执行以下步骤以创建新的 Facebook 应用程序:

  1. 访问 developers.facebook.com/ 并使用您的 Facebook 凭证登录。

  2. 选择 应用,然后选择 创建新应用,如下图所示:如何操作...

    创建一个新的 Facebook 应用程序。

  3. 输入 显示名称命名空间,然后选择一个类别并点击 创建应用,如下图所示:如何操作...

    输入您的 Facebook 应用程序的详细信息。

  4. 转到 设置 并设置 应用程序域,选择一个联系电子邮件并选择平台。

  5. 当您准备好将 Facebook 应用程序发布给公众时,转到 状态与审核,选择 开启 按钮并确认您的选择,如下图所示:如何操作...

    将 Facebook 应用程序发布给所有人

下一步是从用户处获取访问令牌,这将在 Tizen Web 应用程序中使用。通过放置在 Facebook 应用程序设置配置域上的 JavaScript 获取访问令牌的最简单方法只需要三个步骤,如下所示:

  1. 创建一个包含以下源代码的 HTML 文件:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <title>Facebook Authentication</title>
        <script src="img/jquery.min.js"></script>
        <script>
    $( document ).ready(function() {
      var sDelimiter = '#access_token=';
      var nDelimiterPos = document.URL.indexOf(sDelimiter);
      var sAccessToken = 'unknown';
      if (-1 != nDelimiterPos) {
        sAccessToken = document.URL.substring(nDelimiterPos+sDelimiter.length);
      }
      $('#token').text('Facebook access token: ' + sAccessToken);
    });
        </script>
      </head>
      <body>
        <p id="token"></p>
      </body>
    </html>
    
  2. 提供 graph.facebook.com/oauth/authorize?type=user_agent&client_id=<Facebook app ID>&redirect_uri=<Web site>&scope=<Facebook application permissions> URL 给 Facebook 用户,这将把他们重定向到您的网页。

  3. 根据应用程序的设置和需求,将 <Facebook app ID><Web site><Facebook application permissions> 替换为相应的值。所有应用程序使用的 API 所需的权限应列为 scope 参数的值。例如,scope=read_stream,read_mailbox

它是如何工作的

OAuth 2.0 是一种领先的行业标准授权框架。经过多年的努力和大量讨论,规范的最终版本于 2012 年 10 月发布,网址为 tools.ietf.org/html/rfc6749

OAuth 允许第三方应用程序,如 Tizen Web 应用程序,通过 Web 服务代表其所有者访问有限的资源。Facebook Graph API 实现了 OAuth 2.0 标准,通过它,Tizen Web 应用程序可以代表 Facebook 用户发布状态更新。例如,Tizen Web 应用程序必须注册为 Facebook 应用程序,并且必须拥有由用户授予的访问令牌,并具有适当的权限。

Facebook 仍然没有提供 SDK,特别是针对 Tizen。因此,本教程中演示的登录流程是手动构建的。严格遵循 OAuth 2.0,Facebook Graph API 提供了几种不同的方式来创建适用于 Tizen Web 应用程序的授权授权,如下所示:

  • 授权码:在这种情况下,Facebook 应用程序接收到一个代码,然后将其交换为访问令牌。有关此类型授权授权的详细信息,请参见 OAuth 2.0 规范的 1.3.1 节以及使用 Facebook Graph API 的示例实现,网址:developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/

  • 隐式授权:隐式授权流程较简单,但安全性较差。访问令牌通过 HTTP 重定向直接颁发并提供给 Facebook 应用程序。此方法特别适用于 JavaScript 和类似的脚本语言,因为 Facebook 应用程序不需要共享其密钥。有关更多信息,请参考 OAuth 2.0 规范的第 1.3.2 节。

本教程中的示例依赖于隐式授权授予,因为它是使用 JavaScript 实现的。只有客户端 ID、重定向 URL 和一系列所需权限被提供给 Facebook Graph API。成功后,API 会将用户代理重定向回配置的目标,JavaScript 从 URL 中解析出授予的访问令牌。成功后,访问令牌将显示在屏幕上。如果发生错误,则会显示 Facebook 访问令牌:未知 的消息。

本教程中的示例假设 JavaScript 将被放置在网站上。然而,值得一提的是,Facebook 提供了一个替代方案。桌面应用程序可以设置 www.facebook.com/connect/login_success.html 重定向 URL,因此可以直接在 Tizen 应用程序中实现获取访问令牌的解决方案。

另请参阅

获取 Facebook 新闻源

Facebook 最著名且最易识别的功能之一就是其新闻源。每个社交网络用户都熟悉 Facebook 新闻源,因为它包含来自朋友、页面和小组的最新信息。

在本教程中,你将学习如何使用 Graph API 在 Tizen Web 应用程序中检索和显示新闻源。

准备工作

在开始之前,确保你拥有有效的 Facebook 访问令牌。在此示例中,用户必须已经授予应用程序 read_stream 权限。

如何操作...

执行以下步骤,将 Facebook 新闻源集成到 Tizen Web 应用程序中:

  1. 通过将以下行添加到 config.xml 中,允许应用程序访问网站:

    <access origin="*" subdomains="true"></access>
    
  2. 使用 Facebook 访问令牌初始化 JavaScript 变量 sAccessToken,该令牌应按照前一个教程中的说明获取。

  3. 在应用程序的 HTML 中插入 ID 为 listFb 的无序列表:

    <ul id="listFb" data-role="listview"></ul>
    

    实现以下 JavaScript 函数,执行对 Facebook Graph API 的 AJAX 请求:

    function getFacebookNewsFeed(){
      $.ajax({
        type : "GET",
        url  :'https://graph.facebook.com/me/home?access_token=' +sAccessToken,
        success : function(data) {
          for (var nIter in data.data) {
            var sMessage = data.data[nIter].message;
            if (undefined !== sMessage) {
                var sImgSrc = 'http://graph.facebook.com/' + data.data[nIter].from.id + '/picture?type=square';
                var img = $( '<img>', {'src' : sImgSrc, 'style':'float: left; padding-right: 4px;' } );
                var title = $( '<h2>' ).html(data.data[nIter].from.name);
                var text = $('<span>').html(sMessage);
                var listItem = $('<li>').append($( '<p>' ).append(img, title, text));
              $('#listFb').append(listItem);
            }
          }
          $('#listFb').listview('refresh');
        },
        error : function() {
          var listItem = $('<li>').html("Access denied");
          $('#listFb').append(listItem);
          $('#listFb').listview('refresh');
        }
      });
    }
    

它是如何工作的

应用程序使用 Graph API 获取 Facebook 动态,并仅显示包含文本消息的新闻。用户、页面或小组的头像和名称将显示在他们的状态旁边。

它是如何工作的

一个获取 Facebook 新闻动态的 Tizen 应用程序

如果访问令牌文本有问题,屏幕上将显示访问被拒绝

URL 请求使用 jQuery 函数$.ajax()异步发送到 Facebook 服务器。如果成功检索到新闻动态,将收到 JSON,并由与success相关联的函数处理。为每个包含文本消息的页面创建一个无序列表项listFb。将图像、用h2标签标记的标题以及消息的纯文本作为段落添加到列表项中。根据状态作者的唯一 ID,获取 Facebook 个人资料图片。

参见

获取 Facebook 好友列表

友谊是最宝贵的财富,尤其是在 Facebook 上。在本教程中,您将学习如何使用异步 HTTP 请求通过 Facebook Graph API 获取用户的好友列表。每个用户的好友总数、个人头像和全名将显示在示例 Tizen 应用程序的前端界面上。

准备工作

在进行下一个示例之前,请获取一个有效的 Facebook 访问令牌。请求用户好友的 Graph API 时需要权限user_friends

如何做…

执行以下步骤,将获取 Facebook 好友列表的算法集成到 Tizen Web 应用程序中:

  1. 通过将以下行添加到config.xml来启用对网站的访问:

    <access origin="*" subdomains="true"></access>
    
  2. 声明 JavaScript 变量sAccessToken,并将其初始化为用户授予应用程序的 Facebook 访问令牌。

  3. 使用 Tizen Web UI Framework 创建一个 HTML5 文档,其中包含以下代码:

    <div data-role="page">
      <div data-role="header" data-position="fixed">
        <h1>Facebook Friends <span id="labelFbFriendsCount"></span></h1>
      </div><!-- /header -->
    
      <div data-role="content">
         <ul id="listFbFriends" data-role="listview"></ul>
      </div><!-- /content -->
    
      <div data-role="footer" data-position="fixed">
        <h4>Tizen Cookbook</h4>
      </div><!-- /footer -->
    </div><!-- /page
    
  4. 创建以下 JavaScript 函数以获取并排序当前用户的所有好友:

    function compareName(objA, objB) {
      var textA = objA.name.toLowerCase();
      var textB = objB.name.toLowerCase();
      return ((textA < textB) ? -1 : ((textA > textB) ? 1 : 0));  
    }
    
    function getFacebookFriends(){
      $.ajax({
        type : "GET",
        dataType : 'json',
        url : 'https://graph.facebook.com/me/friends?fields=name,picture&access_token='+sAccessToken,
        success : function(data) {
          var friends = data.data.sort(compareName);
          for (var nIter in friends) {  
            var sImg = friends[nIter].picture.data.url;    
            var img = $( '<img>', {'src' : sImg, 'style':'float: left; padding-right: 4px;' } );
            var name = $( '<h2>' ).html(friends[nIter].name);
            var listItem = $('<li>').append($( '<p>' ).append(img, name));
            $('#listFbFriends').append(listItem);
          }
          $('#labelFbFriendsCount').text(' ('+friends.length+')');
          $('#listFbFriends').listview('refresh');
        },
        error : function() {
            var listItem = $('<li>').html("Error");
          $('#listFbFriends').append(listItem);
          $('#listFbFriends').listview('refresh');
        }
      });
    }
    
  5. 执行getFacebookFriends()以请求好友列表。

它是如何工作的

应用程序检索一个人的好友,并按字母顺序显示它们。getFacebookFriends() 函数使用 jQuery 执行一个 AJAX 请求,访问 Facebook Graph API 的/me/friends。每个用户仅请求namepicture字段。

如果 AJAX 请求顺利完成,结果将通过 success 方法进行处理。朋友列表将通过 JavaScript 函数 sort() 按字母顺序排序,并使用 compareName() 函数作为比较器。每个用户的头像和名字将作为一行添加到 ID 为 listFbFriends 的 HTML5 列表中。最后,朋友总数将被添加到页面头部 ID 为 labelFbFriendsCount 的 span 中。

请注意,如果对 Facebook Graph API 的异步请求失败,错误消息将显示在屏幕上。请求失败的原因可能有很多,例如无效的访问令牌或缺少 user_friends 权限。

另请参见

访问 Facebook 个人资料信息

在这个示例中,我们将创建一个应用程序,读取 Linux Foundation 页面上的公开信息。该信息通过 Facebook Graph API 获取。

如何实现...

按照以下步骤使用 Facebook Graph API 检索个人资料信息,并在 Tizen Web 应用程序中显示:

  1. 通过在 config.xml 中添加以下行,允许应用程序访问网站:

    <access origin="*" subdomains="true"></access>
    
  2. 创建一个 ID 为 info 的 HTML div 元素。

  3. 创建一个执行请求到 Facebook 的 JavaScript 函数:

    function getFacebookInfo(sId)
    
    {
      $.ajax({
        type : "GET",
        dataType : 'json',
        url : 'https://graph.facebook.com/'+sId+'?fields=name,about,picture',
        success : function(data) {
          var img = $('<img>',{ 'src': data.picture.data.url, 'style':'float: left; padding: 5px;' });
          var header = $('<h1>').text(data.name);
          var about = $('<p>').text(data.about);
          $('#info').append(img, header, about);
        },
        error : function() {
          $('#info').html('Error');
        }
      });
    }
    
  4. 在源码中的适当位置调用该函数,并传入页面或 Facebook 用户的 ID。例如:

    getFacebookInfo('41911143546');
    

它是如何工作的

该应用程序使用 Facebook 用户 ID 执行异步请求。请求仅检索所选用户的姓名、基本信息和照片。这些字段是公开的,不需要任何权限。如果出现问题,屏幕上将显示带有 错误 文本的标签。

上述示例源代码通过其 ID 41911143546 获取 Linux Foundation 的 Facebook 页面信息。要查找其他页面或个人资料的 ID,请从其 URL 中提取名称,将其附加到 graph.facebook.com/ 的末尾,并从返回的 JSON 中检索 ID。例如,Linux Foundation 的 Facebook 页面是 www.facebook.com/TheLinuxFoundation;因此,其名称是 TheLinuxFoundation,在这种情况下,Graph API 的 URL 应为 graph.facebook.com/TheLinuxFoundation

如果你希望获取当前用户的信息,请在 URL 中使用me而不是用户 ID,并提供一个访问令牌。例如,graph.facebook.com/me?fields=name&access_token=URL 可以获取由访问令牌标识的用户的全名,访问令牌应附加在其末尾。

工作原理

Linux 基金会的 Facebook 页面信息

另请参见

阅读 Facebook 消息

消息是 Facebook 的另一个关键功能,迅速成为全球所有用户流行的功能。在本食谱中,我们将创建一个示例 Tizen 应用程序,用于浏览使用 Facebook Graph API 的对话。

准备就绪

在开始开发以下示例之前,请确保你已获得 Facebook 用户授予的有效访问令牌。执行此操作所需的权限是read_mailbox

操作步骤...

按照以下说明创建一个简单的 Tizen Web 应用程序来浏览 Facebook 消息:

  1. 启动 Tizen IDE 并开始一个新的 Tizen Web 项目。

  2. 从向导的可选项中选择Tizen Web UI FrameworkSingle Page Application

  3. 将以下行附加到config.xml中,以允许访问互联网网站:

    <access origin="*" subdomains="true"></access>
    
  4. index.html的内容替换为以下源代码:

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8"/>
        <meta name="description" content="Sample application for browsing facebook inbox."/>
        <meta name="viewport" content="width=device-width,user-scalable=no"/>
    
        <link rel="stylesheet" href="tizen-web-ui-fw/latest/themes/tizen-white/tizen-web-ui-fw-theme.css" name="tizen-theme"/>
        <title>Facebook Messages</title>
    
        <script src="img/jquery.js"></script>
        <script src="img/tizen-web-ui-fw-libs.js"></script>
        <script src="img/tizen-web-ui-fw.js"
            data-framework-theme="tizen-white"></script>
    
  5. 包含一个与 Facebook Graph API 相关的外部 JavaScript 文件:

      <script type="text/javascript" src="img/facebook.js"></script>
        <script type="text/javascript" src="img/main.js"></script>
        <link rel="stylesheet" type="text/css" href="./css/style.css"/>
    </head>
    
    <body>
        <div data-role="page">
            <div data-role="header" data-position="fixed">
                <h1>Facebook Messages</h1>
            </div><!-- /header -->
    
            <div data-role="content">
    
  6. 在页面的内容中插入一个列表视图和一个按钮:

          <ul id="listFbMessages" data-role="listview"></ul>
          <a href="#" id="btnBack" data-role="button" style="display: none">Back</a>
            </div><!-- /content -->
    
            <div data-role="footer" data-position="fixed">
                <h4>Tizen Cookbook</h4>
            </div><!-- /footer -->
        </div><!-- /page -->
    </body>
    </html>
    
  7. js目录下创建一个名为facebook.js的新文件,并将以下代码保存到该文件中:

    var sAccessToken = '';
    
  8. sAccessToken变量的值替换为 Facebook 用户授予的访问令牌:

    var messages = null;
    
    function bindListItem(obj, nIndex) {
      obj.bind("click", function(event) {
        showFacebookThread(nIndex);
      });
    }
    
    function showFacebookThread(nThreadIndex) {
      var thread = messages[nThreadIndex].comments.data;
      $('#listFbMessages').empty();
      for (var nIter in thread) {  
        var name = $( '<h2>' ).html(thread[nIter].from.name);
        var message = $('<p>').html(thread[nIter].message);
        var listItem = $('<li>').append($( '<div>' ).append(name, message));
        $('#listFbMessages').append(listItem);
      }
      $('#listFbMessages').listview('refresh');
      $('#btnBack').show();
    }
    
    function showMessages() {
      $('#btnBack').hide();
      $('#listFbMessages').empty();
      for (var nIter in messages) {  
        var listItem = $('<li>').append($( '<p>' ).append(messages[nIter].to.data[1].name));
        bindListItem(listItem, nIter);
        $('#listFbMessages').append(listItem);
      }
      $('#listFbMessages').listview('refresh');
    }
    
  9. 继续实现一个 JavaScript 函数,该函数向 Facebook 服务器发出异步请求:

    function getFacebookMessages() {
      $.ajax({
        type : "GET",
        url :'https://graph.facebook.com/me/inbox?access_token=' +sAccessToken,
        success : function(data) {
          messages = data.data;
          showMessages();
        },
        error : function() {
          var listItem = $('<li>').html("Error");
          $('#listFbMessages').append(listItem);
          $('#listFbMessages').listview('refresh');
        }
      });
    }
    
  10. 将以下代码片段附加到main.js文件中的初始化函数:

    getFacebookMessages();
    
    $('#btnBack').bind("click", function(event) {
      showMessages();
    });
    
  11. 保存所有更改并在 Tizen 模拟器或设备上运行该应用程序。

工作原理

该应用程序使用jQuery.ajax()向 Facebook 服务器执行异步 HTTP 请求。因此,应用程序的配置文件中应添加一个访问网站的规则,如步骤 3 所示。

应用程序的用户界面由一个列表和一个返回按钮组成,这些是通过index.html中的 HTML5 创建的。最初,列表是空的,返回按钮是隐藏的。

getFacebookMessages() 函数在应用程序启动时执行。它向 Facebook 服务器发送 HTTP 请求,成功后将接收到的数据存储在变量 messages 中。然后,它调用 showMessages() 函数,显示用户与之通信的人员列表。bindListItem() 函数将这些人的点击与 showThread() 函数关联。Facebook 对话被组织成线程;因此,showThread() 函数的目的是显示选定线程中的所有消息。

后退按钮的 ID 为 btnBack,并在最后一条消息后显示。请注意,按钮仅在用户选择了一个消息线程时才显示。点击按钮时,将调用 showMessages() 函数来隐藏后退按钮,并重新显示联系人的列表。

另见

获取 Facebook 通知

Facebook Graph API 还提供了通过 HTTP 请求管理通知的接口。在本食谱中,你将学习如何检索和处理 Facebook 通知。

准备中

本食谱中的源代码需要 manage_notifications 权限。请从 Facebook 用户获取访问令牌,以授予应用程序此权限。

如何操作...

执行以下步骤将 Graph API 集成到 Tizen Web 应用程序中以获取通知:

  1. 确保通过将以下行添加到 config.xml 来允许访问网站:

    <access origin="*" subdomains="true"></access>
    
  2. 使用有效的 Facebook 访问令牌初始化 JavaScript 变量 sAccessToken

  3. 创建一个 ID 为 listNotifications 的无序 HTML5 列表:

    <ul id="listNotifications" data-role="listview"></ul>
    
  4. 创建一个 JavaScript 函数,发送异步 HTTP 请求到 Facebook 服务器以获取通知:

    function getFacebookNotifications()
    {
      $.ajax({
        type: "GET",
        url: 'https://graph.facebook.com/me/notifications?access_token='+sAccessToken,
        success: function(data) {
          for(var nIter in data.data) {
            var sImgSrc = 'http://graph.facebook.com/' + data.data[nIter].from.id + '/picture?type=square';
            var img = $( '<img>', {'src' : sImgSrc, 'style':'float: left; padding-right: 4px;' } );
            var name = $( '<h2>' ).html(data.data[nIter].from.name);
            var text = $('<span>').html(data.data[nIter].title);
            var listItem = $('<li>').append($( '<p>' ).append(img, name, text));
            $('#listNotifications').append(listItem);
          }
          $('#listNotifications').listview('refresh');
        },
        error: function() {
          $('#listNotifications').append($('<li>').html("Error"));
          $('#listNotifications').listview('refresh');
        }
      });
    }
    
  5. 当你想获取通知并将其加载到列表中时,调用 getFacebookNotifications() 函数。

工作原理

获取通知的 HTTP 请求和 Facebook Graph API 的响应与新闻提要 API 类似。你会注意到,本食谱中的源代码几乎与 获取 Facebook 新闻提要 食谱相同。

getFacebookNotifications() 函数通过 jQuery.ajax() 发起异步 HTTP 请求。成功时,结果会加载到带有 ID 的 HTML 列表中。如果发生错误,错误文本将显示在同一列表中。

另见

更新 Facebook 状态

到目前为止,在本章节中,我们已经讨论了如何获取新闻订阅、朋友列表、个人资料信息、消息和通知。现在,是时候做一些更有趣的事情了。让我们来发布一个 Facebook 状态。

准备工作

通过 Facebook Graph API 代表用户发布内容需要一个有效的访问令牌。根据 Facebook 开发者文档,在向 Facebook 页面发布消息时,必须使用权限 publish_stream。要在用户的时间线发布,必须使用权限 publish_actions

如何做到…

执行以下步骤,创建一个 JavaScript 函数来更新 Tizen Web 应用程序中的 Facebook 状态:

  1. 通过将以下行插入 config.xml 来启用对网站的访问:

    <access origin="*" subdomains="true"></access>
    
  2. 声明一个全局作用域的 JavaScript 变量 sAccessToken,并用有效的访问令牌进行初始化。

  3. 创建一个执行请求到 Facebook 的 JavaScript 函数:

    function updateFacebookStatus(sMessage) {
      $.ajax( {
        url : "https://graph.facebook.com/me/feed",
        type : "POST",
        crossDomain: true,
        data: { access_token: sAccessToken, message: sMessage },
        cache : false,
        success : function(data) {
          if ( (undefined == data) || (undefined != data.error)) {
            console.log('Unable to update status');
          } else {
            console.log("Status updated");
          }
        },
        error : function(error, sStatus, exception) {
          console.log('Error: ' + error.responseText);
        }
      });
    }
    

注意

这只是一个示例。如果你计划在生产代码中使用 updateFacebookStatus() 函数,请将所有 console.log() 执行替换为适当的处理程序。

工作原理

updateFacebookStatus() 函数执行一个异步的 HTTP POST 请求,代表用户通过 Graph API 发布 Facebook 状态。状态的文本作为函数的参数提供。例如,以下代码将尝试将消息 Tizen 发布到用户的时间线:

updateFacebookStatus('Tizen');

本食谱中的示例实现连接了图形用户界面(GUI);因此,操作状态将直接打印到控制台。在成功时,状态已更新的消息将出现在日志中。

另请参见

从 Twitter 中筛选 Tizen 新闻订阅

在本食谱中,我们将征服另一个流行的社交网络。Twitter 于 2006 年推出,作为一个微博平台,并且以每条消息 140 个字符的限制而闻名。这个字符限制是为了与 SMS 短信兼容。

由于安全问题,最近在自定义网站和移动应用程序中使用 Twitter API 变得有些困难。在本食谱中,我们将通过服务器端脚本对用户进行身份验证,然后将获取的数据传递给 Tizen Web 应用程序,该应用程序将使用 JavaScript 处理数据。

准备工作

你需要一个 Twitter 账户来创建应用程序。在继续操作之前,请确保你已经注册了 Twitter。

如何做到…

执行以下步骤,在五分钟内创建一个 Twitter 应用程序:

  1. 访问网站dev.twitter.com/apps/,并使用您的 Twitter 凭据登录。

  2. 点击 创建新应用

  3. 输入 应用程序详情,同意开发者规则,然后点击 创建您的 Twitter 应用程序

    注意

    请注意,在我们的案例中,回调 URL 可以留空。

  4. 点击应用程序的 API 密钥 标签,然后点击 创建我的访问令牌

成功创建 Twitter 应用程序后,您可以继续开发一个服务器端应用程序,将 Twitter 数据传输到移动设备上的 Tizen 应用程序。执行以下步骤创建一个非常简单的 PHP 脚本,用于筛选出关于 #tizen 的 10 条最新推文:

  1. 从 GitHub 下载开源库 TwitterOAuth,并将其放置在服务器上,网址为github.com/abraham/twitteroauth

  2. 创建一个 PHP 脚本,并将以下源代码插入其中:

    <?php
    $sApiKey = '';
    $sApiSecret = '';
    $sAccessToken = '';
    $sAccessTokenSecret = '';
    
    session_start();
    

    使用 PHP 内建函数 require_once() 引入 TwitterOAuth。如果您将库安装在不同的路径中,请更改路径。

    require_once("twitteroauth/twitteroauth/twitteroauth.php");
    
    $twitter = new TwitterOAuth($sApiKey, $sApiSecret, $sAccessToken, $sAccessTokenSecret);
    $result = $twitter->get('https://api.twitter.com/1.1/search/tweets.json?q=%23tizen&count=10&result_type=recent');
    print json_encode($result);
    ?>
    
  3. 在脚本的前几行,将 API 密钥、密钥,以及访问令牌和其密钥赋值给 PHP 变量。

最后,开始开发一个 Tizen 应用程序,它将从 PHP 脚本读取 Twitter 数据并显示给用户。启动 Tizen IDE,并通过以下步骤创建或更新一个新的 Tizen Web 应用程序,或者更新一个现有的应用程序:

  1. 通过将以下行插入 config.xml 来启用服务器访问:

    <access origin="*" subdomains="true"></access>
    
  2. 创建一个 HTML5 无序列表来展示推文:

    <ul id="listTweets" data-role="listview"></ul>
    
  3. 创建一个 JavaScript 函数,从服务器获取数据:

    function getTweets() {
      $.ajax({
        type : 'GET',
    
  4. url 的值替换为您 Twitter 应用程序的 URL:

        url : 'http://anavi.org/twitter.php',
        success : function(data) {
          var tweets = jQuery.parseJSON( data );
          for(var nIter in tweets.statuses) {
            var img = $( '<img>', {'src' : tweets.statuses[nIter].user.profile_image_url, 'style':'float: left; padding-right: 4px;' } );
            var title = $( '<h2>' ).html('@'+tweets.statuses[nIter].user.screen_name);
            var text = $('<span>').html(tweets.statuses[nIter].text);
            var listItem = $('<li>').append($( '<p>' ).append(img, title, text));
            	$('#listTweets').append(listItem);
          }
          $('#listTweets').listview('refresh');
        },
        error : function() {
          var listItem = $('<li>').html("Error");
          $('#listTweets').append(listItem);
          $('#listTweets').listview('refresh');
        }
      });
    }
    
  5. 执行 JavaScript 函数以填充 HTML5 列表:

    getTweets();
    

工作原理

部署在服务器上的 PHP 脚本通过 Twitter REST API v1.1 和开源 PHP 库 TwitterOAuth 获取关于 #tizen 的推文。Tizen Web 应用程序从 PHP 脚本接收数据并将其以列表形式显示,如下图所示。如果失败,用户将看到一个 错误 信息。

工作原理

一个展示关于 #tizen 最新推文的 Tizen Web 应用程序

Twitter REST API v1.1 版本提供了多种方法来管理 Twitter 数据。在这个示例中,使用了 search/tweets 来返回关于 #tizen 的 10 条最近的推文。根据 API 文档,返回的推文数量和哈希标签由 URL 中的 GET 参数 count 和 q 定义:

https://api.twitter.com/1.1/search/tweets.json?q=%23tizen&count=10&result_type=recent

Tizen Web 应用程序使用jQuery.ajax()抓取数据,遍历推文集合,并显示每条推文的文本、用户名和作者的个人资料图片。

另请参见

在 Tizen 中开发 LinkedIn 应用程序

LinkedIn 是最受欢迎的职业社交网络。它是保持职业联系的绝佳工具。尽管人们在 LinkedIn 上花费的时间不如在 Facebook 或 Twitter 上多,但它依然非常有用。

本教程包含了如何创建 LinkedIn 应用程序、如何使用 REST API 以及如何开发服务器端脚本来管理访问令牌。

准备工作

LinkedIn API 的身份验证基于 OAuth 2.0,并且与 Facebook 非常相似。创建 LinkedIn 应用程序的唯一要求是拥有 LinkedIn 账户;因此,在继续之前,请确保您已注册该专业社交网络。

如何操作...

请按照以下简单步骤创建一个 LinkedIn 应用程序:

  1. 访问www.linkedin.com/secure/developer

  2. 点击添加新应用

  3. 输入公司信息和应用程序详细信息。

  4. 配置 OAuth 权限并设置重定向 URL。

  5. 点击保存

创建一个网站用于获取访问令牌。尽管由于安全原因可以通过 JavaScript 实现,但推荐使用服务器端脚本语言,因为 API 密钥必须包含在源代码中。以下教程展示了使用 PHP 的简单实现方法:

  1. 创建一个与重定向 URL 指向位置相对应的 PHP 脚本,并在其中放入以下源代码:

    <?php
    $sApiKey = '';
    $sApiSecret = '';
    $sAppState = '';
    $sAppRedirectUri = '';
    
  2. 将前四个 PHP 变量的值替换为 API 密钥和密钥、一个唯一的长字符串用于 state,以及配置的重定向 URI:

    $sAuthoricationCode = (isset($_GET['code'])) ? $_GET['code'] : '';
    $sState = (isset($_GET['state'])) ? $_GET['state'] : '';
    if ($sAppState != $sState) {
      die('Cross-site request forgery detected.');
    }
    $sUrl = "https://www.linkedin.com/uas/oauth2/accessToken?grant_type=authorization_code&redirect_uri={$sAppRedirectUri}&client_id={$sApiKey}&client_secret={$sApiSecret}&code={$sAuthoricationCode}";
    $data = file_get_contents($sUrl);
    if (FALSE === $data) {
      die('Unable to retrieve access token');
    }
    $data = json_decode($data);
    echo 'Access token: '.$data->access_token;
    ?>
    
  3. 提供以下 URL 给用户进行身份验证:

  4. 替换<API key><redirect URI>为生成的密钥,设置重定向 URI,并为<state>设置一个唯一的长字符串。提供应用程序所需权限的列表,作为<application permission>的值。权限之间用逗号分隔,例如,scope=r_basicprofile,rw_nus

它的工作原理

LinkedIn 认证基于 OAuth 2.0,因此,生成访问令牌的流程包含两个步骤。在第一步中,PHP 脚本获取授权码。然后,在第二步中,授权码被交换为访问令牌。

注意

请注意,Facebook 也支持类似的认证流程,尽管我们在开发 Tizen 平台上的 Facebook 应用的示例中使用的是一种更简单但不太安全的解决方案——隐式授权许可。Facebook 也可以应用通过交换代码获得访问令牌的认证。

隐式授权方式不太安全,因为访问令牌直接颁发给客户端。该解决方案针对在 Web 浏览器中使用 JavaScript 或其他脚本语言实现的客户端进行了优化。有关授权许可的更多信息,请查看提议的 OAuth 2.0 标准中的以下部分:tools.ietf.org/html/rfc6749#section-1.3

该示例仅依赖于 PHP,这是因为作者的个人偏好。如果您愿意,可以使用任何其他服务器端编程语言实现类似的解决方案。请将此示例中的代码作为概念验证,并在计划在生产环境中使用时进行改进。

OAuth 2.0 会将 URL 重定向到应用程序设置中保存的地址,该地址必须与服务器端脚本的位置匹配。初始 URL 的 state 参数是必需的。它充当跨站请求伪造的保护机制。其值应该是一个很长的文本字符串,难以猜测。如果 state 值不匹配,PHP 脚本将退出并显示检测到跨站请求伪造的消息。

成功时,PHP 脚本会在屏幕上打印获取的访问令牌。如果出现错误,则显示无法获取访问令牌的消息。

如下图所示,用户在开始使用 LinkedIn 应用程序时必须授予权限。用户将被告知该应用程序所需的所有权限:

工作原理

授权访问 LinkedIn 应用程序的对话框

权限取决于应用程序将使用的 API。有关可用编程接口及其所需权限的完整列表,可以在developer.linkedin.com/apis查看。

另见

  • LinkedIn 提供了非常好的指南和关于如何使用 OAuth 2.0 进行 API 认证的许多示例。强烈建议您通过浏览developer.linkedin.com/documents/authentication文档,进一步扩展您从本示例中获得的知识。

获取 LinkedIn 更新

本配方包含了使用 LinkedIn REST API 检索用户联系人共享内容的示例用法。包括如何将 API 集成到 Tizen Web 应用程序中并获取最近二十条共享更新的说明。

准备工作

在继续执行此配方之前,必须创建一个 LinkedIn 应用程序并获得访问令牌。如果你还没有创建 LinkedIn 应用程序,请阅读前一个配方进行准备。

如何实现...

LinkedIn API 可以集成到 Tizen Web 应用程序中。例如,以下教程说明了如何显示共享的 LinkedIn 更新列表:

  1. 通过在 config.xml 中插入以下行,允许访问网站:

    <access origin="*" subdomains="true"></access>
    
  2. 在应用程序的 HTML5 内容中插入一个无序列表,以显示 LinkedIn 更新:

    <ul id="listUpdates" data-role="listview"></ul>
    
  3. 实现以下 JavaScript 代码,用于通过 LinkedIn API 检索数据:

    var sAccessToken = '';
    

    将之前 JavaScript 变量的值替换为用户的访问令牌:

    function showLinkedInUpdates() {
      $.ajax({
        type : 'GET',
        url : 'https://api.linkedin.com/v1/people/~/network/updates?type=SHAR&count=20&oauth2_access_token='+sAccessToken,
        headers : { 'x-li-format': 'json' },
        success : function(data) {
          for(var nIter in  data.values) {
            var person =  data.values[nIter].updateContent.person;
           if (undefined != person.currentShare.content) {
              var img = $( '<img>', {'src' : person.pictureUrl, 'style':'float: left; padding-right: 4px;' } );
              var name = $( '<h2>' ).html(person.firstName + ' ' + person.lastName);
              var text = $('<span>').html(person.currentShare.content.title+'<br />'+person.currentShare.content.description+'<br />'+person.currentShare.content.shortenedUrl);
              var listItem = $('<li>').append($( '<p>' ).append(img, name, text));
              $('#listUpdates').append(listItem);
            }
          }
          $('#listUpdates').listview('refresh');
        },
        error : function(data, textStatus) {
          var listItem = $('<li>').html("Error");
          $('#listUpdates').append(listItem);
          $('#listUpdates').listview('refresh');
        }
      });
    }
    

它是如何工作的

使用 jQuery.ajax() 对 LinkedIn 服务器执行异步 HTTPS 请求。URL 根据 LinkedIn API 文档格式化,旨在获取共享和网络更新。访问令牌会附加到以下 URL 的末尾:

'api.linkedin.com/v1/people/~/network/updates?type=SHAR&count=20&oauth2_access_token='

返回结果的数量被设置为 count 参数的值。参数类型定义了更新的过滤条件。在此案例中,仅选择共享更新。支持的类型完整列表可在 developer.linkedin.com/documents/network-update-types 查阅。

在 HTTPS 请求中添加 x-li-format 头部,将 JSON 设置为响应的期望格式。如果数据成功检索,它将加载到 ID 为 listUpdates 的无序 HTML5 列表中。每个共享项的标题、描述和短 URL 将显示出来。更新作者的姓名以及他们的个人资料图片也将显示在列表中。否则,将在屏幕上显示错误消息。

参见

第七章:管理通讯录和日历

本章将介绍以下配方:

  • 检索所有联系人

  • 添加新联系人

  • 删除联系人

  • 导出联系人为 vCard

  • 检索所有任务

  • 创建新任务

  • 删除任务

  • 创建新事件

  • 删除事件

  • 检索所有事件

  • 设置闹钟

介绍

地址簿和日历是功能手机和智能手机上广为人知的应用程序。当然,Tizen 也不例外,这些功能和应用程序已经内置到平台中。通过几个 API,Tizen Web 应用程序可以完全访问这些重要应用程序的数据。

Tizen SDK 带来了 Contacts 和 Calendar API,通过 JavaScript 控制地址簿和日历的内容。这两个 API 都能够创建、更新、删除和读取项目。尽管接口及其方法功能强大,但使用起来非常简单,并将在接下来的 11 个教程中通过大量示例进行解释。

检索所有联系人

本教程提供了如何使用 Tizen Contacts API 检索和显示联系人及其电话号码的教程。

如何实现...

执行以下步骤,将 Contacts API 集成到 Tizen Web 应用程序中,并将所有联系人及其电话号码加载到 HTML5 列表中:

  1. 将以下权限添加到 config.xml 文件中,以允许使用 Contacts API:

  2. 修改应用程序的适当 HTML 文件,例如 index.html,并向其中添加内容和无序列表:

    <ul id="listContacts" data-role="listview"></ul>
    
  3. 将以下源代码放入现有文件中,或创建一个新的 JavaScript 文件:

    function error(err) {
      var listItem = $('<li>').html('Error: '+ err.name + ':' + err.message);
      $('#listContacts').append(listItem);
      $('#listContacts').listview('refresh');
    }
    
    function showContacts(contacts) {
      $('#listContacts').empty();
      var addressBook = tizen.contact.getUnifiedAddressBook();
    
      for (var nIter in contacts) {
        var name = $( '<h2>' ).html(contacts[nIter].displayName);
        var contact = addressBook.get(contacts[nIter].displayContactId);
        var sPhones = '';
        for (var nPhoneIter in contact.phoneNumbers) {
          sPhones += contact.phoneNumbers[nPhoneIter].number + '<br />';
        }
        var phones = $( '<div>' ).html(sPhones);
        var listItem = $('<li>').append($( '<p>' ).append(name, phones));
        $('#listContacts').append(listItem);
      }
      $('#listContacts').listview('refresh');
    }
    
    function retrieveContacts() {
      try {
        tizen.contact.find(showContacts, error);
      } catch (err) {
        error(err);
      }
    }
    
  4. 在应用程序的适当状态下,调用 JavaScript 函数以用数据初始化列表,如下代码所示:

    retrieveContacts();
    

它是如何工作的

JavaScript 函数 retrieveContacts() 调用 Tizen Contacts API 的 find() 方法,并向其传递回调函数,在操作成功或失败时触发。由于没有 contact.read 权限,操作将无法成功完成。如果发生问题,前面的示例实现将在 ID 为 listContacts 的 HTML5 元素中显示错误消息。

它是如何工作的

列出地址簿中的所有联系人

另见

添加新联系人

Tizen Contacts API 提供了几种不同的方法来向地址簿中添加新联系人或更新现有联系人。本教程将带你了解如何收集用户详情并将其保存为新联系人。使用 HTML5 创建简单界面,使用 JavaScript 验证用户输入并将数据存储到地址簿中。

准备工作

在开始教程之前,请确保已将以下权限添加到 Tizen Web 应用程序的 config.xml 中,以便向通讯录添加新内容:

http://tizen.org/privilege/contact.write

add() 方法需要此权限,该方法属于 AddressBook 接口,用于将联系人保存到通讯录中。

如何操作...

按照以下步骤使用 HTML5 创建一个用户界面来收集联系人信息,并使用 JavaScript 保存它们:

  1. 使用 Tizen Web UI Framework 创建页面,通过插入以下 HTML:

    <div data-role="page" id="add">
      <div data-role="header" data-position="fixed">
        <h1>Add New Contact</h1>
      </div><!-- /header -->
    
      <div data-role="content">
        <div data-role="fieldcontain">
          <label for="contactFirstName">First name:</label>
          <input type="text" name="contactFirstName" id="contactFirstName" value=""  />
        </div>
        <div data-role="fieldcontain">
          <label for="contactLastName">Last name:</label>
          <input type="text" name="contactLastName" id="contactLastName" value=""  />
        </div>
        <div data-role="fieldcontain">
          <label for="contactPhone">Phone:</label>
          <input type="tel" name="contactPhone" id="contactPhone" value=""  />
        </div>
        <a href="#" id="buttonSaveContact" data-role="button">Save</a>
        <a href="#list" data-direction="reverse" data-role="button">Back</a>
      </div><!-- /content -->
    
      <div data-role="footer" data-position="fixed">
        <h4>Tizen Cookbook</h4>
      </div><!-- /footer -->
    </div>
    
  2. 创建一个对话框,当发生错误时显示:

    <div id="contactError" data-role="popup" class="center_info">
      <div class="ui-popup-text"> 
        <p id="dialogErrorText"></p>
      </div>
    </div>
    
  3. 实现一个显示带有适当文本的对话框的函数:

    function showErrorPopup(sMsg) {
      $('#popErrorText').text(sMsg);
      $('#contactError').popup('open');
    }
    
  4. 创建一个 JavaScript 函数,用于保存新联系人姓名和电话号码:

    function saveContact(sFirstName, sLastName, sTel) {
      var contact = new tizen.Contact(
        {name: new tizen.ContactName({firstName:sFirstName,
        lastName:sLastName}),
        phoneNumbers:[new tizen.ContactPhoneNumber(sTel)]});
      tizen.contact.getUnifiedAddressBook().add(contact);
    }
    
  5. 在应用程序初始化的函数中,附加以下源代码:

    $('#contactError').popup();
    
    $('#buttonSaveContact').bind( "click", function(event, ui) {
      var sFirstName = $('#contactFirstName').val();
      var sLastName = $('#contactLastName').val();
      var sPhone = $('#contactPhone').val();
      try {
        if ( (0 == sFirstName.length) || (0 == sLastName.length) || (0 == sPhone.length) ) {
          throw new Error('Please enter a name and a phone.');
        }
        saveContact(sFirstName, sLastName, sPhone);
        $.mobile.changePage("#list");
      } catch(err) {
        showErrorPopup(err.message);
      }
    });
    

注意

本食谱中创建的页面可以轻松集成到一个 Tizen Web 应用程序中,该应用程序还包含一个显示所有联系人的页面。请查看随书提供的示例联系人应用程序的源代码。

工作原理

用户界面实现包含在教程第一步中创建的两个组件:一个页面和一个弹出对话框。页面上包含输入框,用于填写新联系人的名字、姓氏以及电话号码。电话号码的输入框类型设置为 tel,这样用户在此字段输入信息时,会自动提供一个便捷的数字键盘。请看下面的截图。这是从随书提供的示例应用程序源代码中截取的截图。

工作原理

用于向 Tizen 通讯录添加新联系人的用户界面

saveContact() 函数从 Contact 接口创建一个 JavaScript 对象,并通过 AddressBook 接口的 add() 方法将其保存到通讯录中。在教程的最后一步,实施了一个处理按钮和初始化对话框的代码。一个验证数据并调用 saveContact() 的函数被绑定到一个文本为 Save 的按钮上。相同的函数会捕捉所有可能发生的异常,并在对话框中将错误信息显示给用户。成功后,以下代码片段会将用户转到之前食谱中创建的 #list 页面:

$.mobile.changePage("#list");

因此,jQuery Mobile 事件 show 会为 #list 页面生成。建议在应用程序初始化时,将此事件绑定到一个重新加载联系人列表的函数上,例如:

$('#list').bind('pageshow', retrieveContacts);

还有更多内容

添加新联系人的另一种方法是通过使用 vCard 格式指定联系人的详细信息,创建一个来自Contact接口的 JavaScript 对象。例如,以下代码片段通过提供的 vCard 3.0 格式的数据,为名为Indiana Jones、电话号码为12345678的人创建一个对象:

var contact = new tizen.Contact(
      "BEGIN:VCARD\n"+
      "VERSION:3.0\n"+
      "N:Jones;Indiana\n"+
      "FN:Indiana Jones\n"+
      "TEL;WORK:12345678\n"+
      "END:VCARD");

如果您想修改通讯录中某人的联系方式,请使用AddressBook接口中的update()函数。其使用方法与add()函数相同,并且必须提供来自Contact接口的 JavaScript 对象作为参数。

另见

删除联系人

一个好的应用程序必须为可能发生的任何灾难做好准备。请记住,任何事情都可能发生,例如,用户可能决定删除前妻的联系方式。幸运的是,Tizen Contact API 非常易于使用。本食谱解释了如何删除单个联系人,甚至删除一批联系人。它还包括如何将联系人删除功能集成到根据本章第一个食谱检索所有联系人开发的应用程序中的教程。

准备工作

具有从通讯录中删除联系人功能的 Tizen Web 应用程序,必须在其config.xml文件中设置以下权限:

http://tizen.org/privilege/contact.write

删除单个联系人所需的权限与remove()函数相同,而removeBatch()函数则用于同时删除多个联系人。

如何实现...

执行以下步骤,以改进前一个食谱中关于检索所有联系人并通过单击删除某人所有联系方式的示例应用:

  1. 启动 Tizen IDE 并加载 Tizen Web 应用程序,以检索所有联系人。

  2. 编辑config.xml并附加删除联系人的所需权限。该文件的源代码中应包含以下行:

    <tizen:privilege name="http://tizen.org/privilege/contact.write"/>
    
  3. 创建一个 JavaScript 函数,从通讯录中删除联系人:

    function deleteContact(contactId) {
      tizen.contact.getUnifiedAddressBook().remove(contactId);
    }
    
  4. 实现一个 JavaScript 函数,处理用户选择并调用上一步创建的函数,传入所选联系人的 ID:

    function bindClick(item, contactId) {
      item.bind("click", function(event) {
        try {
          deleteContact(contactId);
          retrieveContacts();
        } catch(err) {
          showErrorPopup(err.message);
        }
      });
    }
    
  5. 修改retrieveContacts()函数,并将列表项的点击事件绑定到处理程序以删除联系人:

    bindClick(listItem, contact.id);
    

工作原理

bindClick()函数将点击事件绑定到一个匿名函数,该函数会根据联系人 ID 尝试从通讯录中删除某人及其所有联系人。成功时,会调用retrieveContacts()函数重新加载所有联系人列表。如果捕获到异常,错误信息将以弹窗形式显示。

要在应用程序的用户界面中包含删除功能,你必须按照配方第五步中的描述编辑retrieveContacts()函数。bindClick()函数需要两个参数:表示列表项的对象和联系人 ID。它必须在列表项创建后立即调用:

var listItem = $('<li>').append($( '<p>' ).append(name, phones));
bindClick(listItem, contact.id);
$('#listContacts').append(listItem);

Tizen 联系人 API 提供了remove()函数来自AddressBook接口,用于删除联系人。联系人的标识符是此函数的唯一参数。如果未找到联系人或发生其他错误,函数将抛出WebAPIException。记住,每次使用remove()时都要添加异常处理程序,如前面的示例所示。

还有更多

也可以同时删除多个联系人。结合使用find()removeBatch()函数,你可以根据特定的过滤条件删除所有联系人。以下代码示例演示了如何删除所有具有指定名字的联系人:

function printError(err) {
  console.log('Error: '+err.message);
}

function contactsRemoved() {
  console.log('Contacts were removed');
}

function contactsFound(contacts) {
  try {
    var contactsToRemove = new Array();
    for (var nIter in contacts) {
      contactsToRemove.push(contacts[nIter].id);
    }
    addressbook.removeBatch(contactsToRemove, contactsRemoved, printError);
  } catch (err) {
    printError(err);
  }
}

function removeAllContactsWithFirstName(sName) { 
  addressbook = tizen.contact.getDefaultAddressBook();

  var filter = new tizen.AttributeFilter('name.firstName', 'CONTAINS', sName);
  try {
    addressbook.find(contactsFound, printError, filter);
  } catch (err) {
    printError(err);
  }
}

以下示例执行该函数并删除所有名为John的人的联系人:

removeAllContactsWithFirstName('John');

contactsRemoved()函数执行成功。所有可能发生的错误都由printError()函数处理。

应用的AttributeFilter实例使用匹配标志CONTAINS,这确保了对名字进行不区分大小写的字符串比较。该过滤器将选择所有名字为John的联系人以及所有包含"John"的其他名字,例如 Johnny。你可以通过官方文档了解更多关于过滤器和其他可用匹配标志的信息,developer.tizen.org/dev-guide/2.2.1/org.tizen.web.device.apireference/tizen/tizen.html#::Tizen::FilterMatchFlag

另见

  • 本配方中的示例依赖于前几个配方获取所有联系人添加新联系人中的源代码。本书附带了一个结合了这三个配方的示例应用程序的源代码。

将联系人导出到 vCard

你是否已将联系人转移到另一台设备?是否已将手机联系人与电脑或云端同步?是否已将联系人通过电子邮件或 MMS 发送给别人?所有这些操作对于所有智能手机来说都是基本的,它们都需要从通讯录中导出。

本配方将指导你如何使用 Tizen Web 应用程序的联系人 API 序列化并导出通讯录中的数据。

准备工作

本食谱的关键字是 vCard。这是一种用于存储名片信息的标准文件格式,最早出现在 90 年代中期,最初主要用于电子邮件中。如今,vCard 也用于移动设备上的联系人数据序列化和条形码。此格式的几个版本已经被标准化:2.1、3.0 和 4.0。

每个 vCard 都有一个前缀BEGIN:VCARD和后缀END:VCARD。vCard 的版本也应在 vCard 文本的开头指定。标准定义了一组预定义的类型,如FNTITLEADRTEL,以及更多用于描述完整联系人信息的类型。vCard 最常见的文件扩展名是.vcf

如何操作...

从 Tizen 的通讯录中检索一个联系人,并使用convertToString()函数将其导出,如下所示的代码片段:

try {
  var vCard = contact.convertToString('VCARD_30');
  console.log(vCard);
} catch(err) {
  console.log('Error: '+err.message);
}

请注意,在这种情况下,console.log仅作为一个简单示例。在实际应用中,您可以对 vCard 执行多种操作。例如,您可以使用 Tizen 操作 IDtizen.org/appcontrol/operation/share与另一个应用程序共享它。此操作的使用类似于第五章中在外部播放器中启动视频食谱的操作。

它是如何工作的

Contact接口的convertToString()方法有一个参数,指定所需的导出格式。此参数是可选的。自 Tizen 2.2.1 SDK 起,Tizen Contacts API 仅支持 vCard 3.0 版本的导出格式,可以使用字符串VCARD_30进行设置。

约翰·史密斯(John Smith)导出的联系人示例输出,包含电话号码12345678如下:

BEGIN:VCARD
VERSION:3.0
N;CHARSET=UTF-8:Smith;John;;;
FN;CHARSET=UTF-8:John Smith
TEL;TYPE=VOICE;PREF;CHARSET=UTF-8:12345678
END:VCARD

注意

请注意,convertToString()函数在较早版本的 Tizen 平台(如 Tizen 2.0 Magnolia)提供的 Tizen 模拟器中不受支持。如果您的目标是较旧的 Tizen 版本,请在真实设备上测试您的应用程序。

另见

  • 如果您对标准 vCard 格式有更多兴趣,可以参考由互联网工程任务组(IETF)提供的文档:tools.ietf.org/html/rfc6868

检索所有任务

Tizen 日历可以存储任务和事件。这个食谱以及接下来的两个食谱专注于任务。通过这三篇教程(关于查找所有任务、添加任务和删除任务)的结合,最终的结果是一个TO-DO列表的 Tizen Web 应用程序,书中提供了源代码。

准备工作

Tizen SDK 提供了 Tizen Calendar API 来管理任务和事件。两者都是日历项,共享许多属性。本配方不会修改任何数据,因此只需要calendar.read权限。需要向应用程序添加calendar.write权限,才能添加、更改或删除任务和/或事件。

如何实现...

执行以下步骤,将 Calendar API 集成到 Tizen Web 应用程序中,并显示所有任务的列表:

  1. http://tizen.org/privilege/calendar.read权限添加到 Tizen Web 应用程序的config.xml文件中,以读取日历项。

  2. 创建一个 HTML 列表来显示任务:

    <ul id="listTasks" data-role="listview"></ul>
    
  3. 实现以下 JavaScript 函数来检索并显示所有任务:

    function error(err) {
        var listItem = $('<li>').html('Error: '+ err.message);
      $('#listTasks').append(listItem);
      $('#listTasks').listview('refresh');
    }
    function showTasks(tasks) {
      $('#listTasks').empty();
      for (var nIter in tasks) {
        var taskDesc = $( '<h2>' ).html(tasks[nIter].description);
        var taskSummary = $( '<p>' ).html(tasks[nIter].summary);
        var listItem = $('<li>').append($( '<p>' ).append(taskDesc, taskSummary));
        $('#listTasks').append(listItem);
      }
      $('#listTasks').listview('refresh');
    }
    
    function retrieveTasks() {
      try {
        tizen.calendar.getUnifiedCalendar("TASK").find(showTasks, error);
      } catch (err) {
        error(err);
      }
    }
    
  4. 调用retrieveTasks()函数来加载待办事项列表。

工作原理

retrieveTasks()函数通过操作系统中的 Calendar API 的getUnifiedCalendar()函数获取所有日历的集合,确保可以访问所有可用的任务。随后,retrieveTasks()调用find()函数,并提供showTasks()error()作为回调函数。成功时,showTasks()遍历获取的任务数组,并将其以图形方式呈现在 HTML 无序列表中,列表 ID 为listTasks,该列表在第 2 步中创建。使用本配方源代码创建的 Tizen Web 应用程序文件应该如下截图所示:

工作原理

显示所有任务

另见

创建新任务

本章节提供的教程描述了如何向日历中添加新任务。将使用 Tizen Web UI 框架创建一个简单的用户界面,目的是提示输入任务的详细信息。本配方中的源代码使用 Calendar API 访问日历并将数据存储其中。

如何实现...

执行以下步骤,创建一个用户界面以收集任务详细信息并创建新任务:

  1. 在应用程序的config.xml中添加编辑日历事件和任务的权限http://tizen.org/privilege/calendar.write

  2. 使用 HTML5 开发用户界面,收集关于任务的信息。以下源代码展示了一个单页应用,使用 Tizen Web UI 框架提供的小部件创建:

    <div data-role="page" id="add">
      <div data-role="header" data-position="fixed">
        <h1>Add New Task</h1>
      </div><!-- /header -->
    
      <div data-role="content">
        <div data-role="fieldcontain">
          <label for="taskDesc">Description:</label>
          <input type="text" name="taskDesc" id="taskDesc" 
            value=""  />
        </div>
      <div data-role="fieldcontain">
        <label for="taskSummary">Summary:</label>
        <input type="text" name="taskSummary" id="
          taskSummary" value=""  />
      </div>
      <div data-role="fieldcontain">
        <label for="taskDueDate">Due date:</label>
        <input type="date" name="taskDueDate" id="
          taskDueDate" value="" data-format="MMM dd yyyy hh:mm
            tt" value="2012-06-30T00:00:00+09:00"  />
      </div>
    
        <a href="#" id="buttonSaveTask" data-role="button">Save</a>
        <a href="#list" data-direction="reverse" data-role="button">Back</a>
      </div><!-- /content -->
    
      <div data-role="footer" data-position="fixed">
        <h4>Tizen Cookbook</h4>
      </div><!-- /footer -->
    </div>
    
  3. 实现一个用于存储任务的 JavaScript 函数:

    function showErrorPopup(sMsg) {
      $('#dialogErrorText').text(sMsg);
      $('#contactError').popup('open');
    }
    
    function saveTask(sTitle, sSummary, taskDate) {
      var task = new tizen.CalendarTask({description: sTitle, 
                summary: sSummary,
                dueDate: taskDate });
      tizen.calendar.getUnifiedCalendar("TASK").add(task);
    }
    
    function clearForm() {
      $('#taskDesc').val('');
      $('#taskSummary').val('');
    }
    
  4. 将以下源代码附加到应用程序的初始化函数中:

    $('#add').bind( "pageshow", clearForm);
    
    $('#contactError').popup();
    $("#taskDueDate").datetimepicker(); 
    
    $('#buttonSaveTask').bind( "click", function(event, ui) {
      var sTaskDesc = $('#taskDesc').val();
      var sTaskSummary = $('#taskSummary').val();
    
      var dueDateRaw = $("#taskDueDate").datetimepicker("value");
      var dueDate = new tizen.TZDate(Date.parse(dueDateRaw));
    
      try {
        if ( (0 == sTaskDesc.length) || (0 == sTaskSummary.length) ) {
          throw new Error('Please set task details.');
        }
        saveTask(sTaskDesc, sTaskSummary, dueDate);
      } catch(err) {
        showErrorPopup(err.message);
      }
    });
    

工作原理

在第 2 步中创建的用户界面应如下所示:

工作原理

向 Tizen 日历添加新任务

保存 按钮的点击事件由一个 JavaScript 匿名函数处理,该函数在教程的最后一步中实现。此函数收集有关任务摘要、描述和日期的输入信息的值。收集的数据将进行验证,并根据日期的值构造一个 TZDate 对象。如果摘要或描述为空,将显示包含错误信息 请设置任务详细信息 的对话框。

saveTask() 函数被调用来创建新的任务。它获取一个 JavaScript 对象,该对象用于聚合所有日历,并将一个类型为 CalendarTask 的对象传递给其 add() 方法。

请注意,根据文档,add() 方法期望作为参数传入 CalendarItem 的实例。CalendarTaskCalendarEvent 两个接口都实现了 CalendarItem,因此它们的实例可以像代码片段中演示的那样传递给 add() 方法。

还有更多...

Tizen 日历中任务项的类型由 VTODO 格式定义。也可以创建一个表示任务的对象,该对象使用遵循 VTODO 规则格式化的字符串。例如:

var task = new tizen.CalendarTask("BEGIN:VCALENDAR\r\n" +
        "BEGIN:VTODO\r\n" +
        "DESCRIPTION:Champions league\r\n" +
        "SUMMARY:Buy tickets\r\n" +
        "DUE:20140130T134500Z\r\n" +
        "END:VTODO\r\n" +
        "END:VCALENDAR\r\n", "ICALENDAR_20");

另见

删除任务

本章关于日历任务的第三个也是最后一个配方,讲解了如何删除现有任务。

如何做到这一点...

执行以下步骤,在应用程序中实现点击后删除任务,应用程序是按照 检索所有任务 配方中的指示开发的:

  1. 编辑 Tizen Web 应用程序的 config.xml 文件,并添加 http://tizen.org/privilege/calendar.write 权限,以允许修改日历事件。

  2. 实现一个 JavaScript 函数,根据任务名称删除任务:

    function deleteTask(taskId) {
      tizen.calendar.getUnifiedCalendar("TASK").remove(taskId);
    }
    
    function bindClick(item, taskId) {
      item.bind("click", function(event) {
        try {
          deleteTask(taskId);
          retrieveTasks();
        } catch(err) {
          showErrorPopup(err.message);
        }
      });
    }
    
    function showErrorPopup(sMsg) {
      $('#dialogErrorText').text(sMsg);
      $('#contactError').popup('open');
    }
    
  3. showTasks() 函数中创建列表项后,附加以下代码行,以便将任务的点击事件与 delete 函数连接:

    bindClick(listItem, tasks[nIter].id);
    

工作原理

remove() 函数是 Calendar API 中 Calendar 接口的一部分,用于从日历中完全删除任务或事件。如代码片段所示,deleteTask() 函数是所有可用日历的聚合实例,首先检索设备上的所有日历,之后执行 remove() 函数。任务的 ID 被指定为其参数。

在这个示例中,bindClick() 函数被用来通过 jQuery 提供的 .bind() 方法将列表中任何项目的点击事件与 deleteTask() 函数连接起来。

另请参见

创建新事件

本示例提供了一些使用 Tizen Calendar API 添加新事件的代码片段。事件由 CalendarEvent 接口描述。该接口包含 CalendarItem 接口的所有属性,并且具有额外的属性 endDateavailabilityrecurrenceRule

准备工作

Calendar API 的相同函数用于添加或更新事件和任务。如预期的那样,无论应用程序是修改事件还是任务,都必须将相同的权限添加到 Tizen Web 应用程序的 config.xml 文件中。

如何做...

Tizen Calendar API 提供了两种添加新事件的方式。第一种方法是使用 JSON 设置事件详情,如以下代码片段所示:

var calendar = tizen.calendar.getUnifiedCalendar("EVENT");
var event = new tizen.CalendarEvent({description:'TuxCon',
  summary:'Conference about free and open source software', 
  startDate: new tizen.TZDate(2014, 6, 28, 10, 0), 
  duration: new tizen.TimeDuration(8, "HOURS"),
  location:'Plovdiv, Bulgaria'});
calendar.add(event);

第二种方法依赖于 VEVENT 格式。实现并运行以下源代码,从按照 VEVENT 规则格式化的字符串创建一个事件:

var calendar = tizen.calendar.getUnifiedCalendar("EVENT");
var event = new tizen.CalendarEvent("BEGIN:VCALENDAR\r\n" +
    "BEGIN:VEVENT\r\n" +
    "DTSTAMP:20140422T1000Z\r\n" +
    "DTSTART:20140627T1900Z\r\n" +
    "DTEND:20140627T2330Z\r\n" +
    "SUMMARY:Friday beer event\r\n" +
    "CATEGORIES:MEETING\r\n" +
    "END:VEVENT\r\n" +
    "END:VCALENDAR", "ICALENDAR_20");
calendar.add(event);

另请参见

  • 有关 Calendar 接口的 add()update() 函数的更多信息和示例用法,请参见 创建新任务 示例

删除事件

这个示例展示了如何使用 Calendar API 提供的 remove() 方法来删除一个事件。

准备工作

用于从 Tizen 日历中删除事件的函数需要以下权限:

tizen.org/privilege/calendar.write

如果应用程序需要删除事件,请确保此权限已被添加到应用程序的配置文件中。

如何做...

以下是 deleteEvent() 函数的示例实现,演示了如何从 Tizen 的统一日历中删除一个事件:

function deleteEvent(nEventId) {
  try {
    var calendar = tizen.calendar.getUnifiedCalendar("EVENT");
    calendar.remove(nEventId);
  } catch (err) {
    console.log('Error: '+err.message);
  }
}

它是如何工作的

remove()函数在处理事件时的使用方法与处理任务时相同。根据文档,函数期望接收类型为CalendarItemId的参数,该参数可以是CalendarEventIdCalendarTaskId。在此特定情况下,它必须是CalendarEventId,因为deleteEvent()函数移除的是事件。由于参数类型错误、无效的标识符、安全问题、事件丢失或其他未知错误,remove()函数可能会失败。对于这些错误,每个都会抛出一个异常,并在附带的代码片段中捕获并打印在控制台上。

另见

  • 再次查看删除任务的配方,了解如何将remove()函数集成到 Tizen Web 应用程序的用户界面中

检索所有事件

本配方提供了如何在 Tizen Web 应用程序中使用日历 API 查找所有事件的说明。提供的示例代码片段与检索所有任务的配方中的代码相似。它展示了如何按事件摘要的字母顺序列出所有事件。

如何实现...

执行以下步骤以查找 Tizen Web 应用程序中所有可用的事件:

  1. 确保应用程序拥有读取日历事件的权限,通过在配置文件config.xml中添加http://tizen.org/privilege/calendar.read权限。

  2. 在应用程序的 HTML5 内容中插入一个无序列表:

    <ul id="listEvents" data-role="listview"></ul>
    
  3. 实现 JavaScript 函数以检索和显示事件的基本信息,如以下代码所示:

    function error(err) {
      var listItem = $('<li>').html('Error: '+ err.message);
      $('#listTasks').append(listItem);
      $('#listTasks').listview('refresh');
    }
    function showEvents(events) {
      $('#listEvents').empty();
      for (var nIter in events) {
        var taskDesc = $( '<h2>' ).html(events[nIter].description);
        var taskSummary = $( '<p>' ).html(events[nIter].summary);
        var listItem = $('<li>').append($( '<p>' ).append(taskDesc, taskSummary));
        $('#listEvents').append(listItem);
        deleteEvent(events[nIter].id);
      }
      $('#listEvents').listview('refresh');
    }
    
    function retrieveEvents() {
      try {
        var sort = new tizen.SortMode('summary', 'ASC');
        tizen.calendar.getUnifiedCalendar("EVENT").find(showEvents, error, null, sort);
      } catch (err) {
        error(err);
      }
    }
    
  4. 在合适的时机执行该函数,例如,在应用启动时使用以下单行代码:

    retrieveEvents();
    

工作原理

日历 API 检索事件的行为几乎与检索任务时相同。如您所见,本配方中的函数和变量名称与检索所有任务配方中的名称相似。

retrieveEvents()函数获取统一的日历并按摘要升序排序事件。回调函数showEvents()error()作为第一个和第二个参数传递给find()函数。其他两个参数是可选的。第三个参数传递null,因为应该检索所有事件。如果您希望根据某种标准检索部分事件,请提供AbstractFilter接口的实例,而不是null。此外,通过SortMode接口构造的对象定义了排序属性。

当操作成功时,检索到的日历事件数组会传递给showEvents()函数,该函数将其描述和摘要加载到具有 ID 为listEvents的 HTML5 无序列表中。如果发生问题,error()函数将在相同的列表中显示相关细节。

另见

设置提醒

Tizen 日历 API 允许开发者为任务和事件设置提醒。在这个教程中,你将学习如何构造 CalendarAlarm 接口的对象,以及如何

使用它们。

准备工作

设置提醒的 Tizen Web 应用需要拥有 calendar.write 权限。如果应用需要查找现有的日历项并更新其提醒,则还需要 calendar.read 权限。在这种情况下,编辑 config.xml 并添加以下权限,以确保应用程序正常工作:

如何实现...

使用以下代码片段,通过绝对日期和时间来创建一个提醒:

var alarmDate = new tizen.TZDate(2014, 9, 24, 8, 0, 0);
var alarm = new tizen.CalendarAlarm(alarmDate, "SOUND", "Reminder: Buy gifts!");

或者,你可以在事件发生之前,或者任务的到期日前创建一个提醒,使用相对时间持续量,例如:

var alarm = new tizen.CalendarAlarm(new tizen.TimeDuration(2, "HOURS"), "DISPLAY", "Reminder: meeting in two hour!");

提醒必须附加到事件或任务的属性上。例如,可以将一个名为 alarmCalendarAlarm 实例分配给一个名为 eventCalendarEvent 实例,如以下代码所示:

event.alarms = [alarm];
calendar.update(event);

工作原理

如本教程所示,日历 API 提供了两种不同的方式来创建 CalendarAlarm 接口的实例。在第一个示例中,通过 TZDate 对象提供日期和时间的绝对值,并将其传递给 alarmDate 对象的构造函数。第二个示例通过使用 TimeDuration 接口的实例,定义事件发生前的时间持续量,以触发提醒。

通知方式必须作为 CalendarAlarm 构造函数的一个参数显式指定。可用的选项如下:

  • SOUND:用户通过声音提醒来接收通知

  • DISPLAY:此选项会在设备屏幕上显示消息,而不播放任何声音

可以在创建提醒时提供带有描述的字符串作为可选参数。

参见

第八章:通信

在本章中,我们将涵盖以下食谱:

  • 发送短信

  • 发送电子邮件

  • 接收和显示电子邮件

  • 浏览通话历史

  • 使用蓝牙

  • 使用 NFC 并检测其他设备

  • 发送 NDEF 消息

  • 接收 NDEF 消息

  • 接收推送通知

简介

现代电信技术提供了一套丰富的无线数据交换标准。本章中的食谱将指导您如何利用 Tizen API 创建能够通过不同通信通道使用多种网络承载体进行通信的 Tizen Web 应用程序。

每个食谱都提供了简单的示例。没有包含任何复杂用户界面的源代码,重点放在 API 的使用上。

发送短信

第一条短信于 1992 年 12 月 3 日由软件程序员 Neil Papworth 在英国发送。从那时起,短信(SMS)成为了最受欢迎的短信服务,现在,无论是功能手机还是智能手机都可以使用短信服务。

由于历史原因,我认为短信应该获得本书本章中第一个讨论的通信通道的荣誉。在这个食谱中,您将学习如何在 Tizen Web 应用程序中使用 Messaging API 发送短信。

准备工作

Messaging API 提供了管理电子邮件以及通过电信协议(如短信和多媒体短信)传输的消息的工具。使用它的 Tizen Web 应用程序根据使用的方法需要额外的权限。根据 API 方法执行的操作,已经定义了两种类型的权限:tizen.org/privilege/messaging.read用于查找消息和对话以及与消息相关的监听器设置,tizen.org/privilege/messaging.write则用于执行其他操作,如同步、发送、删除消息等。

如何操作……

执行以下步骤以实现发送短信的 JavaScript 函数:

  1. 编辑config.xml文件,并附加以下权限:

    tizen.org/privilege/messaging.write

  2. 创建一个全局的 JavaScript 对象来存储消息的详细信息,如下所示:

    var message = { plainBody: "", to: [] };
    
  3. 创建以下回调函数:

    function logError(err) {
       console.log("Error: " + err.message);
    }
    
    function sentOK(recipients)
    {
      for (var nIter in recipients) {
        console.log("Message sent to " + recipients[nIter]);
      }
    }
    
    function retrieveServices(services) {
      var msg = new tizen.Message("messaging.sms",message);
      services[0].sendMessage(msg, sentOK, logError);
    }
    
  4. 实现一个函数,以发送短信到一个电话号码,如下所示:

    function sendSMS(sTxt, sPhone) {
      message.plainBody = sTxt;
      message.to.push(sPhone);
      tizen.messaging.getMessageServices("messaging.sms", retrieveServices, logError);
    }
    
  5. 当您想通过指定接收者的电话号码发送短信时,执行sendSMS()函数:

    sendSMS("Hello", "12345678");
    

它是如何工作的……

函数sendSMS()接收文本消息和电话号码作为参数,并将其存储在全局 JavaScript 对象message中。消息的文本通过对象message的属性plainBody进行设置,电话号码则作为该属性的第一个元素存储在数组中。然后,sendSMS()调用消息 API 的getMessageServices()方法,并设置函数retrieveServices()logError(),分别在操作成功或失败时调用。

注意

如果要将相同的消息发送给多个收件人,可以将更多的电话号码添加到该属性中。

有关消息所有属性的更多详细信息,请参阅MessageInit接口的文档,地址为developer.tizen.org/dev-guide/2.2.1/org.tizen.web.device.apireference/tizen/messaging.html#::Messaging::MessageInit

函数retrieveServices()构建 SMS 消息,并使用sendMessage()方法发送它们。该方法需要在教程的第一步设置的tizen.org/privilege/messaging.write权限。

执行错误代码时可能发生的任何问题都会由函数logError()处理,该函数会在控制台中打印错误并跟踪问题的详细信息。

请注意,依据您的订阅计划,移动网络运营商会对每条发送的短信收取标准的短信费用。如果没有网络覆盖或设备启用了飞行模式,您将无法成功发送短信。

另见

  • 请参考下一个教程,了解如何使用相同的消息 API 方法发送电子邮件。

发送电子邮件消息

使用消息 API 发送电子邮件的方式类似于发送短信。这个教程将演示如何发送电子邮件,并讨论发送短信和电子邮件之间的差异。

准备就绪

从 Tizen 版本 2.2.1 开始,消息 API 能够发送 SMS、MMS 和电子邮件。这三种选项在枚举类型MessageServiceTag中定义,该枚举由 API 定义。与 SMS 方法一样,必须使用sendMessage()方法发送电子邮件,它也需要tizen.org/privilege/messaging.write权限。

在继续之前,请确保设备和模拟器已连接到互联网,并且已设置电子邮件帐户。

要设置电子邮件,请启动设备主屏幕上的电子邮件应用程序,或者导航到设置 | 帐户 | 添加 | 电子邮件,并按照屏幕上的说明操作。请查看以下截图:

准备就绪

在 Tizen 设备上设置电子邮件

操作步骤...

执行以下步骤,从 Tizen 网络应用程序发送电子邮件:

  1. 编辑 config.xml 文件,并附加以下权限:

    tizen.org/privilege/messaging.write

  2. 创建一个全局 JavaScript 对象,能够存储消息中的所有信息,如下所示:

    var msgEmail = { subject: "", plainBody: "", to: [], cc: [] };
    
  3. 实现回调函数,如下代码所示:

    function logError(err) {
       console.log("Error: " + err.message);
    }
    
    function sentOK(recipients)
    {
      for (var nIter in recipients) {
        console.log("Message sent to " + recipients[nIter]);
      }
    }
    
    function retrieveServices(services) {
      var msg = new tizen.Message("messaging.email",msgEmail);
      services[0].sendMessage(msg, sentOK, logError);
    }
    
  4. 创建一个 JavaScript 函数来发送电子邮件:

    function sendEmail(sSubject, sTxt, sTo, sCC) {
      msgEmail.subject = sSubject;
      msgEmail.plainBody = sTxt;
      msgEmail.to.push(sTo);
      msgEmail.cc.push(sCC);
      tizen.messaging.getMessageServices("messaging.email", retrieveServices, logError);
    }
    
  5. 指定所需的参数,并在应用程序的适当位置调用 sendEmail() 函数,例如:

    sendEmail("Hello", "Hello World", "foo@example.com", "bar@example.com");
    

工作原理...

前面的示例将带有主题 Hello 和内容 Hello World 的电子邮件发送到 <foo@example.com>,并将抄送发送到 <bar@example.com>。如你所见,源代码与之前发送短信的指南非常相似。主要的区别在于 JavaScript 对象 msgEmail 的属性、方法 getMessageServices() 的第一个参数的值,以及 Message 构造函数,它已被设置为 message.email

对象 msgEmail 的结构遵循 MessageInit 接口所描述的属性。还可以使用 bcc 属性指定密件抄送电子邮件,或者使用 htmlBody 属性为电子邮件设置 HTML 内容。所有的属性,to、cc 和 bcc,都是数组,任何一个属性都可以存储多个电子邮件。

API 还支持附件。所有附加的文件必须提供给 Message 接口实例的 attachments 属性,例如:

var msg = new tizen.Message("messaging.email",msgEmail);
msg.attachments = [new tizen.MessageAttachment("image.png", "image/png"), new tizen.MessageAttachment("note.txt", "text/plain")];

每个附件都会创建一个 MessageAttachment 实例。文件通过其文件名和 MIME 类型来描述。

另见

接收和显示电子邮件消息

通过消息 API 的功能,可以在 Tizen 网络应用程序中监控和检测消息、对话以及消息文件夹的变化。在本指南中,你将找到创建一个应用程序来检测新电子邮件的相关指南。

准备工作

必须提供互联网连接,并且在 Tizen 设备上配置电子邮件帐户,才能测试和验证本指南中创建的应用程序是否正常工作。如果你还没有设置电子邮件,请根据之前指南中的说明进行设置。

如何实现...

按照以下教程中的步骤,实施一个监听器来接收 Tizen 网络应用程序中的新电子邮件:

  1. 编辑应用程序的 config.xml 文件,并添加以下权限以读取消息:

    tizen.org/privilege/messaging.read

  2. 声明以下全局 JavaScript 变量:

    var gEmailListenerId, gEmailService;
    
  3. 创建 JavaScript 函数,以显示检索到的电子邮件或发生的错误,如下所示:

    function showError(err) {
      console.log("Error: " + err.message);
    }
    
    function displayMessages(messages) {
      for (var nIter in messages) {
        var message = messages[nIter];
        console.log("From: " + message.from + " Subject: " + message.subject);
      }
    }
    
  4. 实现初始化电子邮件服务并监听消息的 JavaScript 函数,如下所示:

    function registerEmailListener() {
      var messagesListener = {
        messagesadded : displayMessages,
        messagesupdated : function(messages) {},
        messagesremoved : function(messages) {},
      };
      gEmailListenerId = gEmailService.messageStorage.addMessagesChangeListener(messagesListener);
    }
    
    function retrieveServices(services) {
      try
      {
        if (0 == services.length) {
          throw new Error("Email service not found.");
        }
        gEmailService = services[0];
        registerEmailListener();
      } catch (err) {
        showError(err);
      }
    }
    
    function initEmailService() {
      try {
        tizen.messaging.getMessageServices("messaging.email", retrieveServices);
      } catch (err) {
        showError(err);
      }
    }
    
  5. 实现一个函数,注销电子邮件监听器:

    function unregisterEmailListener() {
      try {
        gEmailService.messageStorage.removeChangeListener(gEmailListe nerId);
      } catch (err) {
        showError(err);
      }
    }
    
  6. 在应用程序的源代码中适当位置开始监听电子邮件,如下所示:

    initEmailService();
    

注意

提供的代码片段是简单的示例,它们与任何图形用户界面无关。接收到的电子邮件信息或任何错误会打印在控制台上。

它是如何工作的...

监控电子邮件需要三个阶段,如下所示:

  • 获取电子邮件消息服务

  • 监听消息变化

  • 显示消息

第一阶段由函数initEmailService()执行。如果成功,算法的下一步是执行函数registerEmailListener()。最终阶段由函数displayMessages()执行,它作为回调由接口MessageStorage的方法addMessagesChangeListener()调用。请注意,教程第四步的代码片段仅显示已添加到MessageStorage中的消息。

还有更多内容...

Tizen 的 Messaging API 还提供了监听与会话和消息文件夹相关变化的方法。请注意,会话可以表示电子邮件通信或聊天。它们通过电子邮件的主题和聊天的发送者及接收者进行分组。

接口MessageStorageaddConversationsChangeListener()addFoldersChangeListener()方法应被用来检测与会话和文件夹相关的变化。它们的用法与在本教程中代码片段中使用的addMessagesChangeListener()方法类似。

另见

  • 本书随附一个基于教程的 Tizen Web 应用程序示例。它具有一个简单的用户界面,显示收到的电子邮件的发件人和主题,如下图所示。你可以查看应用程序的源代码以了解更多细节。另见

    显示收到的电子邮件的示例应用程序

浏览通话历史

在本教程中,你将学习如何使用 Tizen 的 Call History API 来访问和浏览你的通话记录。一本示例应用程序也提供了,能够检索最近拨打的电话列表。

如何做到这一点...

执行以下步骤以在 Tizen Web 应用程序中实现 CallHistory API,并检索拨打的电话号码:

  1. config.xml中添加以下权限以读取通话记录:

    tizen.org/privilege/callhistory.read

  2. 实现 JavaScript 函数以显示通话记录并处理错误,如下所示:

    function showError(err) {
      console.log("Error: " + err.message);
    }
    
    function showCalls(calls) {
      try {
        for (var nIter in calls) {
          var call = calls[nIter];
          var sTel = (undefined != call.remoteParties[0]) ? call.remoteParties[0].remoteParty : '';
          console.log('TEL: ' + sTel + ' Date: ' + call.startTime.toLocaleTimeString() + " " + call.startTime.toLocaleDateString());
        }
      } catch (err) {
        showError(err);
      }
    }
    
  3. 创建函数来检索外拨电话,如下所示:

    function getOutgoingCalls() {
      try {
        var filter = new tizen.AttributeFilter("direction", "EXACTLY", "DIALED");
        var order = new tizen.SortMode("startTime", "DESC");
        tizen.callhistory.find(showCalls, showError, filter, order, 10);
      } catch(err) {
        showError(err);
      }
    }
    
  4. 在应用程序启动时或任何其他适当的地方调用函数 getOutgoingCalls()

    getOutgoingCalls();
    

如何工作...

函数 getOutgoingCalls() 使用接口 CallHistoryfind 方法来检索前十个外拨电话。结果按日期和时间降序排列。创建一个 AttributeFilter 实例,只选择 DIALED 的号码。方向属性允许的其他选项有:

  • RECEIVED:这是用于接听来电

  • MISSEDNEW:这是指尚未查看的未接来电

  • MISSED:这是指所有未接来电

  • BLOCKED:这是指被阻止的通话

  • REJECTED:这是指用户已拒绝的通话

在前面的示例中,函数 showCalls() 成功时作为回调执行。否则,在失败时,问题由函数 showError() 处理。

本书提供了一个基于此配方的示例 Tizen 网页应用程序,集成了 HTML5 用户界面。以下屏幕截图来自此应用程序。你可以通过将其与上一章分析过的 Contacts API 结合来改进示例应用程序。

如何工作...

最近拨出的电话号码列表

还有更多...

一些 Tizen 网页应用程序可能需要具有监控通话的能力。在这种情况下,你可以使用接口 CallHistory 的方法 addChangeListener()removeChangeListener()。必须为函数 addChangeListener() 提供一个观察者。成功时,此函数返回一个标识符,该标识符在需要移除监听器时作为参数传递给 removeChangeListener() 函数。

另见

使用蓝牙

蓝牙是一种流行的无线标准,用于近距离设备之间的数据传输。该标准的名称来源于中世纪丹麦和挪威国王 Harald "Bluetooth" Gormsson 的昵称。

本配方提供了关于 Tizen 网页应用程序的蓝牙 API 的详细信息,并解释了如何在以下情况下使用它:

  • 发现蓝牙设备

  • 连接到另一个蓝牙设备

  • 连接并通过蓝牙传输数据

准备工作

本配方中使用的蓝牙 API 方法需要以下权限:

在继续进行下一部分之前,请将所有权限添加到您的 Tizen web 应用程序的 config.xml 文件中。

如何操作...

执行以下步骤,以便在 Tizen web 应用程序中发现、连接并通过蓝牙交换数据:

  1. 声明并初始化全局 JavaScript 变量,代码如下:

    var g_bluetoothAdapter = null;
    var g_bIsServer = false;
    

    变量 bIsServer 仅用于确定应用程序是作为服务器还是客户端运行。请查看以下代码:

    var g_sUUID = '6BEE80ED-D05C-4B44-A329-E7441FEE9154';
    

    蓝牙服务发现协议SDP)定义了一系列可用的 UUID。使用 GNU/Linux 或 OS X 操作系统的 Tizen 开发人员可以在控制台中执行命令 uuidgen 来生成全局唯一标识符UUID)。

    如果您的应用程序需要连接并与蓝牙串口板通信,您可以尝试使用 SDP 定义的基本 UUID,00000000-0000-1000-8000-00805F9B34FB

  2. 创建一个简单的函数来记录错误,代码如下:

    function showError(err) {
      console.log("Error: " + err.message);
    }
    
  3. 打开蓝牙并按照以下示例代码片段检索蓝牙设备:

    function initBluetooth() {
      g_bluetoothAdapter = tizen.bluetooth.getDefaultAdapter();
      if(false == g_bluetoothAdapter.powered) {
        g_bluetoothAdapter.setPowered(true, run);
      }
      else
      {
    

    此时,将调用 JavaScript 函数 run()。其实现将在本食谱的下一步骤中提供:

        run();
      }
    }
    

    您还可以创建一个关闭蓝牙的函数。以下是实现该功能的示例:

    function shutDownBluetooth() {
      if(true == g_bluetoothAdapter.powered) {
        g_bluetoothAdapter.setPowered(false);
      }
    }
    
  4. 创建 JavaScript 数据来读取从蓝牙套接字接收到的数据。它将在服务器和客户端模式下使用。请查看以下代码:

    function readMessage(socket) {
      var data = socket.readData();
      var sResult = '';
      for (var nIter = 0; nIter < data.length; nIter++) {
        sResult += String.fromCharCode(data[nIter]);
      }
      $('#labelInfo').text(sResult);
    }
    
  5. 实现 JavaScript 函数,注册服务、与客户端建立连接,并在应用程序以服务器模式运行时接收数据,代码如下:

    function registerServer(recordHandler) {
      console.log("Bluetooth services registered!");
      recordHandler.onconnect = function(socket) {
        console.log("Client connected: " + socket.peer.name + "," + socket.peer.address);
    
        socket.onmessage = function() {
          readMessage(socket);
        };
    
        socket.onclose = function() {
          console.log('The socket was closed.');
        };
      };
    }
    
    function startService() {
      if (true == g_bIsServer) {
        g_bluetoothAdapter.registerRFCOMMServiceByUUID(g_sUUID, "TizenCookbook",
            registerServer, showError);
      }
    }
    
  6. 实现扫描和配对设备的 JavaScript 函数。这些函数将在应用程序以客户端模式运行时使用。请查看以下代码:

    function paired(device) {
      try {
        console.log('Paired with device ' + device.name + ' (address: ' + device.address + ')');
    

    请注意,如果找到的设备没有提供具有预期 UUID 的服务,则会抛出异常。如果一切正常,回调函数 onSocketConnected() 将被调用,如以下代码所示:

        if (-1 == device.uuids.indexOf(g_sUUID)) {
          throw new Error('UUID not found');
        }
    
        if (false == g_bIsServer) {
          device.connectToServiceByUUID(g_sUUID, onSocketConnected, showError);
        }
      } catch (err) {
        showError(err);
      }
    }
    

    以下函数尝试在两台设备之间建立配对,如果成功,则调用回调函数 paired()

    function pairDevices(sAddress) {
      g_bluetoothAdapter.createBonding(sAddress, paired, showError);
    }
    
    function discoverBluetoothDevices() {
      try {
        console.log('searching...');
        var bluetoothDevices =
        {
          ondevicefound: function(device) {
            console.log('Bluetooth device: ' + device.name + ' address: ' + device.address);
            pairDevices(device.address);
          }
        };  
        g_bluetoothAdapter.discoverDevices(bluetoothDevices, showError);
      } catch (err) {
        showError(err);
      }
    }
    
  7. 创建一个回调函数,将数据从客户端发送到服务器,代码如下:

    function onSocketConnected(socket) {
      console.log("Bluetooth socket created successfully.");
      socket.onmessage = function () { readMessage(socket); };
      socket.onclose = function() { };
      if ( (null != socket) && ("OPEN" == socket.state) ) {
        console.log('sending data to the server');
        var sMessage = 'Hello World';
        var sendData = [];
        for (var nIter = 0; nIter < sMessage.length; nIter++)
        {
          sendData[nIter] = sMessage.charCodeAt(nIter);
        }
        socket.writeData(sendData);
      }
    }
    
  8. 实现一个函数,根据用户设置的首选项以服务器模式或客户端模式运行应用程序,代码如下:

    function run() {
      if (true == g_bIsServer) {
        console.log('running as a server...');
        startService();
      } else {
        console.log('running as a client...');
        discoverBluetoothDevices();
      }
    }
    
  9. 在两台不同的 Tizen 设备上构建并运行应用程序。将其在第一台设备上以服务器模式启动,在第二台设备上以客户端模式启动。

它是如何工作的...

根据本食谱中提供的说明,可以创建一个使用蓝牙 API 的 Tizen web 应用程序,该应用程序可以同时作为服务器和客户端运行。以下截图来自与本书一起提供的示例应用程序:

它是如何工作的...

简单的 Tizen 蓝牙应用程序

在服务器模式下,应用程序通过函数startService()注册一个具有唯一 UUID 的服务,接收来自客户端的文本消息,并使用回调执行的函数readMessage()将其显示在屏幕上。

当应用程序处于客户端模式时,它使用接口BluetoothAdapterdiscoverDevices()方法开始搜索附近的蓝牙设备。相同的接口还提供了getKnownDevices()方法,能够检索已知设备的列表。

函数paired()将两个设备绑定在一起,只有当找到的设备提供与配方第一步中配置的 UUID 相匹配的服务时,才会建立连接。

接口BluetoothSocketreadData()writeData()方法用于通过已打开的蓝牙套接字发送和接收数据。发送文本消息之前,必须将其转换为字节数组,如函数onSocketConnected()中所示。接收到消息时,需要进行相反的操作。例如,函数readMessage()中的代码片段将字节数组转换为字符串。

在此示例中,客户端仅发送一条消息,其内容硬编码为Hello World

本配方中的代码片段可以轻松改进并调整以适应其他用例,例如通过蓝牙进行聊天。请注意,示例应用程序的源代码并未准备好用于生产环境,其主要目的是演示如何简单地使用蓝牙 API。

另见

使用 NFC 并检测其他设备

近场通信NFC)是一种基于射频识别RFID)的短程无线通信标准。与其他通信技术(如蓝牙)相比,NFC 具有几个独特的优势。NFC 不需要任何设置即可连接设备,建立连接的唯一要求是设备距离大约 4 厘米(或更短)。NFC 的另一个重要优势是对无源标签不需要任何电源供应。

NFC 标签也被称为智能标签或信息标签。它们存储的数据可以轻松被用户读取。在许多情况下,它们的使用方式类似于二维码和其他类型的条形码。任何人都可以购买空白 NFC 标签并将自定义信息保存到其中。

根据标准,NFC 的使用可以根据模式分为三大类,具体如下:

  • 读写器模式,适用于与被动 NFC 兼容标签交换数据。例如,海报、贴纸和其他促销商品上的二维码可以用被动 NFC 标签替代。

  • 点对点模式,允许设备之间进行数据交换。

  • 卡模拟模式,允许 NFC 设备作为卡片被外部读卡器访问。例如,这一功能在非接触式支付中可能非常方便。

在本配方中,你将学习如何打开 NFC 设备以及如何搜索近距离内的其他设备。随后的两个配方将专注于发送和接收数据。

准备就绪

使用本配方中展示的 NFC 功能的 Tizen Web 应用程序,必须在其config.xml文件中具有以下权限:

对于在点对点模式下工作的应用程序,还需要以下权限:

使用读写器模式的应用程序还应包含以下权限:

如何操作...

执行以下步骤,以使用 NFC API 在 Tizen Web 应用程序中建立两个支持 NFC 的设备之间的点对点连接:

  1. 声明并初始化全局 JavaScript 变量,用于获取 NFC 适配器和 NFC 设备:

    var g_nfcAdapter = null;
    var g_nfcDevice = null;
    
  2. 创建NFCPeerDetectCallback接口的实例,该实例实现onattach()ondetach()方法,如下所示:

    var peerFound = {
        onattach : function(nfcPeer) {
              console.log("NFC Target found");
              },
    
        ondetach : function() {
            console.log("NFC Target is detached");
        }
    };
    
  3. 开发 JavaScript 函数来处理错误,例如:

    function showError(err) {
      console.log("Error: " + err.message);
    }
    
  4. 创建 JavaScript 函数以打开 NFC 设备并搜索附近的其他 NFC 设备:

    function findTarget() {
      try {
        g_nfcAdapter.setPeerListener(peerFound, showError);
      } catch (e) {
        showError(err);
      }
    }
    
    function initNFC() {
      try {
        g_nfcAdapter = tizen.nfc.getDefaultAdapter();
        g_nfcAdapter.setPowered(true, findTarget, showError);
      } catch (err){
        showError(err);
      }
    }
    
  5. 调用以下函数以启动建立 NFC 连接的过程:

    initNFC();
    

注意

调试利用 NFC API 的 Tizen 应用程序的最简单方法是使用事件注入器。通过导航至 Tizen IDE 中的窗口 | 显示视图 | 事件注入器,并选择Nfc标签来启用它。

它是如何工作的...

本配方中实现的算法获取NFCAdapter接口的实例,使用setPeerListener()方法搜索其他 NFC 设备,并通过peerFound中实现的回调函数与检测到的设备建立连接。

顺便提一下,这个 JavaScript 对象是接口NFCPeerDetectCallback的实例。onattach()方法在检测到另一个 NFC 设备时调用,并接收接口NFCPeer的实例作为参数。

还有更多...

必须连接到 NFC 标签的 Tizen Web 应用程序必须采用类似的方法。唯一的区别是应该使用setTagListener()方法,而不是setPeerListener(),成功回调由接口NFCTagDetectCallback描述。请注意,此接口的方法名称与NFCPeerDetectCallback相同。然而,在这种情况下,onattach()的参数是接口NFCTag的实例。

参见

发送 NDEF 消息

NFC 数据交换格式NDEF)是一种用于通过 NFC 传输数据的二进制格式。本示例演示了如何创建一个 NDEF 消息,将其以点对点模式与另一个 NFC 设备共享,或将其写入一个被动 NFC 标签。

准备工作

如果你计划在点对点模式下进行通信,请包含权限tizen.org/privilege/nfc.p2p,如果计划写入 NFC 标签,则包含权限tizen.org/privilege/nfc.tag

如何执行...

执行以下步骤来发送 NDEF 消息:

  1. 创建一个 NDEF 消息。例如,以下函数使用接口NDEFMessageNDEFRecordText的实例创建一个 UTF-16 字符编码的文本 NDEF 消息:

    function createNDEFMessage(sTxt) {
      var ndefRecord = new tizen.NDEFRecordText(sTxt, 'en-US', 'UTF16');
      var records = [ndefRecord];
      return new tizen.NDEFMessage(records);
    }
    

    注意

    Tizen NFC API 支持三种不同类型的 NDEF 记录:文本、URI 和 MIME。为每种支持的类型提供了一个单独的接口。接口NDEFRecordTextNDEFRecordURINDEFRecordMedia实现了基础接口NDEFRecord

  2. 写入或发送消息。使用接口的writeNDEF()方法将信息存储到 NFC 标签中,如下代码所示:

    tag.writeNDEF(createNDEFMessage('foo'));
    
  3. 使用接口的sendNDEF()方法将信息以点对点模式传输到另一个设备。请查看以下示例:

    nfcPeer.sendNDEF(createNDEFMessage('bar'));
    

请注意,成功或失败时将调用的回调函数可以选择作为writeNDEF()sendNDEF()的参数指定。这两个方法在出错时都会抛出异常,因此调用时必须加入 try/catch 块。

参见

接收 NDEF 消息

前面的两个食谱演示了如何与 NFC 建立连接以及如何写入/发送数据。下一步是探索 Tizen NFC API 的能力,以读取/接收数据。

准备工作

当在 NFC 的点对点模式中接收到 NDEF 消息时,需要使用权限tizen.org/privilege/nfc.p2p。如果你计划实现从被动 NFC 标签读取数据的功能,则必须在config.xml文件中包含权限tizen.org/privilege/nfc.tag。请注意,如前面的食谱中所述,发送消息和写入标签信息也需要相同的权限。

操作方法...

请使用接口NFCTag提供的readNDEF()方法读取来自被动 NFC 标签的数据,如以下示例所示:

  1. 创建一个函数,如果找到支持的 NDEF,将作为回调函数被调用,如下所示:

    function readMessage(message)
    {
      console.log("Number of retrieved records: " + message.recordCount);
    }
    
  2. 实现一个函数来处理可能发生的任何错误,如下所示:

    function printError(err) {
      console.log("Error: " + err.message);
    }
    
  3. 使用以下代码片段读取标签的内容:

    try {
      if (tag.isSupportedNDEF) {
        tag.readNDEF(readMessage, printError);
      }
    } catch (err) {
      printError(err);
    }
    

在 Tizen Web 应用程序中,如果在 NFC 点对点模式下进行通信,则可以监听传入的 NDEF 消息。例如,以下代码片段扩展了使用 NFC 并检测其他设备食谱中的第二步源代码:

var peerFound = {
    onattach : function(nfcPeer) {
      console.log("NFC Target found");
      nfcPeer.setReceiveNDEFListener({
        onsuccess: function(message) {
          console.log("Number of retrieved records: " + message.recordCount);
        }
      });
    },

    ondetach : function() {
      console.log("NFC Target is detached");
    }
};

新添加的代码行以加粗形式显示。方法setReceiveNDEFListener()用于监听传入的 NDEF 消息。一个匿名 JavaScript 函数,该函数接收NDEFMessage接口的实例作为参数,被赋值给onsuccess方法。

工作原理...

readNDEF()的第二个参数是可选的,但建议提供以处理执行过程中可能发生的错误。还建议将方法包围在 try/catch 块中,因为它可能抛出异常。

在读取被动 NFC 标签的示例中,NDEFMessage的一个实例将作为readMessage()函数的参数提供。成功时调用的函数也会提供该类的一个实例。在点对点模式下调用的函数也会提供相同的实例。NDEFMessage的属性记录包含一个数组,其中包含NDEFRecord的实例。可以通过属性tnf检查每个记录的指定类型,tnf存储了类型名称字段TNF)的 3 位值。根据文档,至少支持以下值:

  • NFC_RECORD_TNF_EMPTY

  • NFC_RECORD_TNF_WELL_KNOWN

  • NFC_RECORD_TNF_MIME_MEDIA

  • NFC_RECORD_TNF_URI

  • NFC_RECORD_TNF_EXTERNAL_RTD

  • NFC_RECORD_TNF_UNKNOWN

  • NFC_RECORD_TNF_UNCHANGED

另请参见

接收推送通知

Tizen 提供了一种机制,可以从应用服务器触发事件,并将这些事件传递到 Tizen 设备上。需要接收这些事件通知的 Tizen Web 应用程序必须使用并利用 Push API。

例如,如果您希望从您的网站向运行在用户设备上的 Tizen Web 应用程序发送通知,您必须将通知发送到推送服务,推送服务将其转发到 Tizen 设备。一旦设备收到通知,您的 Tizen 应用程序应处理该消息。

准备工作

Tizen 中的推送服务由三星提供。在开始应用程序开发之前,您必须申请访问该服务。

根据Push Service Request的流程,开发者必须发送电子邮件至<push.tizen@samsung.com>。请求应包含开发者和应用程序信息。请阅读文档中关于 Tizen Web 应用程序的最新信息和请求表单详细内容:developer.tizen.org/dev-guide/2.2.1/org.tizen.native.appprogramming/html/guide/messaging/push_service_request.htm

如何操作...

按照以下步骤将 Push API 集成到 Tizen Web 应用程序中:

  1. config.xml中添加权限 tizen.org/privilege/push,并允许从推送服务器的域名访问,如下所示:

    <tizen:privilege name="http://tizen.org/privilege/push"/>
    <access origin="https://{region}.push.samsungosp.com:8088" subdomains="true"/>
    

    注意

    替换 {region} 并设置一个与所使用服务器位置相对应的值,具体取决于 regID 的前两位数字。有关更多详情,请访问 developer.tizen.org/dev-guide/2.2.1/org.tizen.native.appprogramming/html/guide/messaging/push_server_api.htm

  2. 创建一个 JavaScript 函数来处理错误和异常,代码如下:

    function printError(err) {
      console.log("Error: " + err.message);
    }
    
  3. 创建一个 JavaScript 函数来处理推送服务注册成功的情况,代码如下:

    function registerServiceOK(id)
    {
      console.log('Service with id: ' + id + ' registered.');
    }
    
  4. 使用以下代码注册服务:

    var service = null;
    try {
      service = new tizen.ApplicationControl("http://tizen.org/appcontrol/operation/push_test");
      tizen.push.registerService(service, registerServiceOK, printError);
    } catch (err) {
      printError(err);
    }
    
  5. 创建一个 JavaScript 函数来处理传入的通知,代码如下:

    function notificationReceived(notification)
    {
      console.log("Notification received: " + notification.alertMessage);
    }
    
  6. 连接到推送服务并接收消息,代码如下:

    try {
      tizen.push.connectService(notificationReceived, printError);
    } catch (err) {
      printError(err);
    }
    

工作原理

如果在应用程序运行时收到通知,它会立即处理。如果应用程序未运行或在后台运行,则会显示一个通知标记,并在应用程序图标旁显示未读通知的数量。

要利用 Push API 并接收推送通知,您必须首先使用 PushManager 接口的 registerService() 方法,在 Tizen Web 应用程序的设备上注册推送服务。

此后,应用程序必须使用相同接口的 connectService() 方法连接到服务。在之前的代码片段中,每收到一条消息,都会将 PushMessage 的实例传递给 notificationReceived() 函数。notificationReceived() 函数作为回调由 connectService().connectiService() 调用。

还有更多...

要将网站或服务的通知发送到 Push API 的服务器,请执行 HTTPS POST 请求到 https://{region}.push.samsungosp.com:8088/spp/pns/api/push。请按照食谱第一步中的指南,替换 {region}。请求的头部应包含应用程序的 ID (appID) 和密钥 (appSecret) 信息。请求体必须包含 regIDrequestIDmessageappData

例如,以下代码片段演示了如何使用 JavaScript 和 jQuery 向推送服务器发送 HTTPS POST 请求:

jQuery.ajax({
  type: 'POST',
  contentType: 'json',
  url: 'https://euwest.push.samsungosp.com:8088/spp/pns/api/push',
  headers: { "appID": sAppId, "appSecret": sAppSecret },
  data: JSON.stringify({ "regID": sRegId, "requestID":"000001", "message":"badgeOption=SET&badgeNumber=10&action=ALERT&alertMessage=Foo", "appData":"Bar" }),
  dataType: 'json',
})

通知发送到位于欧盟西部地区的 Tizen 服务器,通知包含文本 Bar 和通知标记 Foo。应用程序的 ID 和密钥通过 JavaScript 变量 sAppIdsAppSecret 提供。变量 sRegId 存储应用程序的注册 ID。

有关将网站和服务与推送服务器集成的更多细节,请访问 developer.tizen.org/dev-guide/2.2.1/org.tizen.native.appprogramming/html/guide/messaging/push_server_api.htm

注意

顺便提一下,Tizen 推送 API 使用的服务器与 Bada 中的推送消息服务相同。这一巧合并不令人惊讶,因为在 2013 年,三星将其 Bada 操作系统合并到了开源平台 Tizen 的第二个主要版本中。

另见

第九章:使用传感器

在本章中,我们将涵盖以下主题:

  • 使用基于位置的服务来显示当前位置

  • 获取路线

  • 地理编码

  • 逆地理编码

  • 计算距离

  • 检测设备运动

  • 检测设备方向

  • 使用振动 API

介绍

Tizen 设备的硬件传感器提供的数据对于许多移动应用非常有用。在本章中,你将学习如何使用辅助 GPS 获取 Tizen 设备的地理位置,如何检测设备的方向和运动变化,以及如何将地图服务集成到 Tizen Web 应用中。

大多数与地图和导航相关的示例使用 Google API。其他服务提供商,如诺基亚 HEREOpenStreetMapYandex,也提供具有类似功能的 API,可以作为在 Tizen Web 应用中替代 Google 的选择。

本书撰写时,诺基亚 HERE 宣布加入 Tizen 联盟。一些 Tizen 设备将预装由诺基亚 HERE 提供的导航应用。智能手表 Gear S 是三星首款内置诺基亚 HERE 开发的 Navigator 应用的 Tizen 可穿戴设备。如果你有兴趣将其集成到 Tizen Web 应用中,可以探索诺基亚 HERE JavaScript API 的全部功能:developer.here.com/javascript-apis

OpenStreetMap 也值得特别关注,因为它是一个高质量平台,且成功的社区驱动项目。OpenStreetMap 的主要优势在于其使用完全免费。本章中的逆地理编码配方演示了通过 Google 和 OpenStreetMap API 两种不同方式进行地址查询。

使用基于位置的服务来显示当前位置

通过遵循本配方中提供的示例,你将掌握 HTML5 地理定位 API,并学习如何在 Tizen Web 应用中获取设备当前定位的坐标。

准备工作

确保开启定位功能。在 Tizen 设备或模拟器上,打开设置,选择位置,并打开GPS(如果可用)和网络定位,如下所示的截图:

准备工作

启用 Tizen 设置中的 GPS 和网络定位

如何操作...

按照以下步骤在 Tizen Web 应用程序中获取位置:

  1. 实现 JavaScript 来处理错误:

    function showError(err) {
      console.log('Error ' + err.code + ': ' + err.message);
    }
    
  2. 实现 JavaScript 来处理获取到的位置:

    function showLocation(location) {
      console.log('latitude: ' + location.coords.longitude + ' longitude: ' + location.coords.longitude);
    }
    
  3. 实现一个 JavaScript 函数,使用 HTML5 地理位置 API 搜索当前位置:

    function retrieveLocation() {
      if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(showLocation, showError);
      }
    }
    
  4. 在应用程序源代码的适当位置,调用前一步创建的函数:

    retrieveLocation();
    

工作原理

HTML5 地理位置 API 的getCurrentPosition()方法在retrieveLocation()函数中用于获取设备当前位置信息的坐标。showLocation()showError()函数作为回调函数提供,在成功或失败时调用。Position接口的一个实例作为参数传递给showLocation()。该接口有两个属性:

  • coords:指定一个定义获取到的位置的对象

  • timestamp:指定获取位置时的日期和时间

getCurrentPosition()方法接受一个PositionOptions接口的实例作为第三个可选参数。此参数用于设置特定选项,如enableHighAccuracytimeoutmaximumAge。如果你想了解更多关于该接口属性的细节,可以查看Geolocation API 规范

无需在config.xml中显式添加任何特定权限。当实现了本食谱代码的应用程序首次启动时,它将请求访问位置的权限,如以下截图所示:

工作原理

在 Tizen Web 应用程序中请求访问位置

如果你正在开发基于位置的应用程序并希望使用 Tizen 模拟器进行调试,请使用事件注入器设置位置。

还有更多内容...

Google Maps JavaScript API v3 提供的地图视图可以轻松嵌入到 Tizen Web 应用程序中。使用该 API 需要互联网连接,但无需从 Google 安装额外的 SDK 或工具。按照以下说明显示地图和标记:

  1. 确保应用程序可以访问 Google API。例如,可以通过向config.xml添加以下行来启用对任何网站的访问:

    <access origin="*" subdomains="true"></access>
    
  2. 访问code.google.com/apis/console获取 API 密钥。

  3. 点击服务并激活Google Maps API v3

  4. 然后,点击API并复制浏览器应用程序的密钥。其值将在应用程序的源代码中使用。

  5. 实现以下源代码,在 ID 为map-canvasdiv中显示地图:

    <style type="text/css">
      #map-canvas { width: 320px; height: 425px; }
    </style>
    <script type="text/javascript" src="img/strong>&sensor=false"></script>Replace <API Key> in the line above with the value of the key obtained on the previous step.
    
    <script type="text/javascript">
    function initialize(nLatitude, nLongitude) {
      var mapOptions = {
        center: new google.maps.LatLng(nLatitude, nLongitude),
        zoom: 14
      };
      var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
    
      var marker = new google.maps.Marker({
        position: new google.maps.LatLng(nLatitude, nLongitude),
        map: map
      });
    }
    </script>
    
  6. 在应用程序的 HTML 中,创建以下div元素:

    <div id="map-canvas"></div>
    
  7. 向该函数提供纬度和经度,并在适当的位置执行它。例如,这是伦敦威斯敏斯特的一个位置的坐标:

    initialize(51.501725, -0.126109);
    

以下截图演示了按照前述指南创建的 Tizen Web 应用程序:

更多内容...

在 Tizen Web 应用中使用 Google Maps

将本食谱中 How to do it 部分的教程与这些指令结合,显示带有当前位置的地图。

另见

获取路线

导航是移动应用中的另一个常见任务。Google Directions API 允许 Web 和移动开发人员通过发送 HTTP 请求来获取位置之间的路线。必须指定起点和终点,但也可以设置途经点。所有位置可以通过精确的坐标或地址提供。本食谱演示了如何获取路线并步行到达目的地的示例。

准备工作

在开始开发之前,注册一个应用并获取 API 密钥:

  1. 登录 Google 开发者控制台,网址是 code.google.com/apis/console

  2. 点击 服务 并启用 Directions API

  3. 点击 API 访问 并获取 服务器应用的密钥,该密钥应在您的 Tizen Web 应用程序向 API 发送的所有请求中使用。

有关 Directions API 的 API 密钥的更多信息,请访问 developers.google.com/maps/documentation/directions/#api_key

如何操作...

使用以下源代码来获取并显示如何通过 Google Directions API 从一个位置步行到另一个位置的逐步指令:

  1. 通过在 config.xml 中添加以下行来允许应用访问网站:

    <access origin="*" subdomains="true"></access>
    
  2. 创建一个 HTML 无序列表:

    <ul id="directions" data-role="listview"></ul>
    
  3. 创建一些 JavaScript 来加载获取的路线:

    function showDirections(data) {
      if (!data || !data.routes || (0 == data.routes.length)) {
        console.log('Unable to provide directions.');
        return;
      }
      var directions = data.routes[0].legs[0].steps;
      for (nStep = 0; nStep < directions.length; nStep++) {	
        var listItem = $('<li>').append($( '<p>' ).append(directions[nStep].html_instructions));
        $('#directions').append(listItem);
      }
      $('#directions').listview('refresh');
    }
    
  4. 创建一个 JavaScript 函数,向 Google Maps API 发送异步 HTTP(AJAX)请求以获取路线:

    function retrieveDirection(sLocationStart, sLocationEnd){
      $.ajax({
        type: 'GET',
        url: 'https://maps.googleapis.com/maps/api/directions/json?',
        data: { origin: sLocationStart,
            destination: sLocationEnd,
            mode: 'walking',
            sensor: 'true',
            key: '<API key>' },
    

    不要忘记用 Google 为 Directions API 提供的 服务器应用的密钥 值替换 <API key>。请注意,类似的密钥也必须在后续使用 Google APIs 的源代码中设置:

        success : showDirections,
        error : function (request, status, message) {
        console.log('Error');
        }
      });
    }
    
  5. 提供起点和终点位置作为参数,并执行retrieveDirection()函数。例如:

    retrieveDirection('Times Square, New York, NY, USA', 'Empire State Building, 350 5th Avenue, New York, NY 10118, USA');
    

工作原理

第一步是允许 Tizen Web 应用访问 Google 服务器。之后,构造一个 ID 为 directions 的 HTML 无序列表。起点和终点传递给 JavaScript 函数retrieveDirections()。成功后,回调函数showDirections()会被调用,并加载从起点到终点的逐步指示。以下截图显示了一个 Tizen Web 应用,指导如何从纽约的时代广场步行到帝国大厦:

工作原理

Directions API 是相当灵活的。必选参数包括origin(起点)、destination(终点)和sensor。还可以通过不同的参数在 HTTP 请求中配置许多其他选项。要设置所需的交通方式,请使用参数mode,其有以下选项:

  • driving(驾车)

  • walking(步行)

  • bicycling(骑行)

  • transit(通过公共交通获取路线)

默认情况下,如果没有指定模式,其值将设置为driving(驾车)。

单位制可以通过参数unit进行配置。提供metric(公制)和imperial(英制)两种选项。开发者还可以使用参数avoid定义限制条件,并通过waypoints参数提供一个或多个方向点的地址。如果提供多个地址,使用管道符号(|)分隔。

还有更多…

也可以使用 Nokia HERE 的服务创建具有类似功能的路线规划应用。REST API 可以像 Google Maps API 一样使用。首先在developer.here.com/get-started获取凭证。

应发送一个异步 HTTP 请求来获取路线。如何构造向 REST API 发送请求的说明,请参考其文档:developer.here.com/rest-apis/documentation/routing/topics/request-constructing.html

Nokia HERE JavaScript API 是另一种优秀的路线规划解决方案。通过该 API 提供的DisplayManager类实例化,创建地图和路线管理器。然后,创建一个包含路径点的列表,路径点的坐标由Coordinate类的实例定义。请参考 API 用户手册中提供的以下示例,了解详情:developer.here.com/javascript-apis/documentation/maps/topics/routing.html

关于类DisplayManagerCoordinate的完整规格说明可以在以下链接查看:

另见

地理编码

地理编码 是检索与地址相关的地理坐标的过程。它通常用于需要地图和提供导航的移动应用程序。在本步骤中,你将学习如何通过 JavaScript 和 AJAX 请求调用 Google Geocoding API,将地址转换为经度和纬度。

准备工作

在使用 Tizen Web 应用程序中的 Geocoding API 之前,你必须获取 API 密钥:

  1. 访问 Google Developers Console:code.google.com/apis/console

  2. 点击 服务 并开启 Geocoding API

  3. 点击 API 访问 获取 服务器应用密钥 的值。然后在所有来自你 Tizen Web 应用程序的请求中使用该密钥。

有关 Geocoding API 的 API 密钥的更多详细信息,请访问 developers.google.com/maps/documentation/geocoding/#api_key

如何操作...

按照以下步骤,在 Tizen Web 应用程序中使用 Google Geocoding API 获取地址的地理坐标:

  1. 通过将以下行添加到 config.xml 文件中,允许应用程序访问网站:

    <access origin="*" subdomains="true"></access>
    
  2. 创建一个 JavaScript 函数来处理 API 提供的结果:

    function retrieveCoordinates(data) {
      if (!data || !data.results || (0 == data.results.length)) {
        console.log('Unable to retrieve coordinates');
        return;
      }
      var latitude = data.results[0].geometry.location.lat;
      var longitude = data.results[0].geometry.location.lng;
      console.log('latitude: ' + latitude + ' longitude: ' + longitude);
    }
    
  3. 创建一个 JavaScript 函数,向 API 发送请求:

    function geocoding(address) {
      $.ajax({
        type: 'GET',
        url: 'https://maps.googleapis.com/maps/api/geocode/json?',
        data: { address: address,
          sensor: 'true',
          key: '<API key>' },
    

    如同之前的步骤,你需要再次将 <API key> 替换为 Google 提供的 服务器应用密钥,该密钥用于 Geocoding API。

        success : retrieveCoordinates,
        error : function (request, status, message) {
        console.log('Error: ' + message);
        }
      });
    }
    
  4. 将地址作为参数传递给 geocoding() 函数并调用它。例如:

    geocoding('350 5th Avenue, New York, NY 10118, USA');
    

工作原理

地址作为参数传递给 geocoding() 函数,后者将向 Google Geocoding API 的 URL 发送请求。该 URL 指定返回的结果应以 JSON 格式序列化。URL 中的参数包含关于地址和 API 密钥的信息。此外,还有一个参数指示设备是否具有传感器。一般来说,Tizen 移动设备配备有 GPS,因此传感器参数设置为 true

API 返回成功响应后,由retrieveCoordinates()函数处理,该函数作为回调函数执行。处理完数据后,本示例中的代码片段会在控制台打印出检索到的坐标。例如,如果我们将帝国大厦的地址提供给geocoding()函数,在成功时,控制台将打印以下文本:纬度:40.7481829 经度:-73.9850635

另见

逆向地理编码

逆向地理编码,也称为地址查询,是通过地理坐标描述的位置来检索对应地址的过程。

Google 地理编码 API 提供了地理编码和逆向地理编码的方法。在本教程中,你将学习如何使用 Google API 和 OpenStreetMap 提供的 API,根据坐标查找位置的地址。

准备工作

地理编码和逆向地理编码需要相同的密钥。如果你已经获得了前面教程中的密钥,可以直接在这里使用。如果没有,你可以执行以下步骤:

  1. 访问 Google 开发者控制台,网址为code.google.com/apis/console

  2. 前往服务并启用地理编码 API

  3. 选择API 访问,找到服务器应用密钥的值,并在所有来自 Tizen Web 应用程序对 API 的请求中使用它。

如果你需要更多关于地理编码 API 密钥的信息,请访问developers.google.com/maps/documentation/geocoding/#api_key

如何操作...

按照所描述的算法,使用 Google Maps 地理编码 API 根据地理坐标检索地址:

  1. 允许应用程序访问网站,可以在config.xml中添加以下行:

    <access origin="*" subdomains="true"></access>
    
  2. 创建一个 JavaScript 函数来处理检索到的地址数据:

    function retrieveAddress(data) {
      if (!data || !data.results || (0 == data.results.length)) {
        console.log('Unable to retrieve address');
        return;
      }
      var sAddress = data.results[0].formatted_address;
      console.log('Address: ' + sAddress);
    }
    
  3. 实现一个函数,通过向 Google 服务器发出请求来根据纬度和经度检索地址:

    function reverseGeocoding(latitude, longitude) {
      $.ajax({
        type: 'GET',
        url: 'https://maps.googleapis.com/maps/api/geocode/json?',
        data: { latlng: latitude+','+longitude,
            sensor: 'true',
            key: '<API key>' },
    

    注意,<API key>必须替换为 Google 为地理编码 API 提供的服务器应用密钥

        success : retrieveAddress,
        error : function (request, status, message) {
        console.log('Error: ' + message);
        }
      });
    }
    
  4. 提供坐标作为函数的参数并执行,例如:

    reverseGeocoding('40.748183', '-73.985064');
    

它是如何工作的

如果使用之前的源代码开发的应用调用 reverseGeocoding() 函数,传入纬度 40.748183 和经度 -73.985064,控制台打印的结果将是 350 5th Avenue, New York, NY 10118, USA。顺便提一下,和之前的配方一样,这个地址对应的是位于纽约的帝国大厦。

reverseGeocoding() 函数向 API 发送 AJAX 请求。URL 中的参数指定响应必须以 JSON 格式返回。位置的经度和纬度由逗号分隔,并设置为 URL 中 latlng 参数的值。

还有更多...

OpenStreetMap 还提供反向地理编码服务。例如,以下 URL 将返回一个纬度为 40.7481829、经度为 -73.9850635 的位置的 JSON 结果:

nominatim.openstreetmap.org/reverse?format=json&lat=40.7481829&lon=-73.9850635

OpenStreetMap 的主要优势在于它是一个开源项目,并且拥有一个庞大的社区。它的反向地理编码 API 不需要任何密钥,且可以免费使用。

Leaflet 是一个基于 OpenStreetMap 的流行开源 JavaScript 库,专为移动设备优化。它得到了良好的支持且易于使用,因此你可以考虑将其集成到 Tizen 网络应用程序中。可以在 leafletjs.com/features.html 探索它的功能。

另见

计算距离

本配方专注于计算两个位置之间距离的方法。将再次使用 Google Directions API。与获取方向配方不同,这次只会处理关于距离的信息。

准备工作

就像与 Google API 相关的其他配方一样,在这种情况下,开发者必须在开发开始前获取 API 密钥。请按照以下说明进行注册并获取适当的 API 密钥:

  1. 访问 Google 开发者控制台 code.google.com/apis/console

  2. 点击服务并开启地理编码 API

  3. 点击API 访问并保存服务器应用的密钥。在所有来自 Tizen 网络应用程序的 API 请求中使用该密钥。

如果你需要关于方向 API 的更多信息,请访问 developers.google.com/maps/documentation/directions/#api_key

如何做...

按照以下步骤计算两个位置之间的距离:

  1. 通过将以下行添加到config.xml,允许应用程序访问网站:

    <access origin="*" subdomains="true"></access>
    
  2. 实现一个 JavaScript 函数,用于处理获取到的数据:

    function retrieveDistance(data) {
      if (!data || !data.routes || (0 == data.routes.length)) {
        console.log('Unable to retrieve distance');
        return;
      }
      var sLocationStart = data.routes[0].legs[0].start_address;
      var sLocationEnd = data.routes[0].legs[0].end_address;
      var sDistance = data.routes[0].legs[0].distance.text;
      console.log('The distance between ' + sLocationStart + ' and ' + sLocationEnd + ' is: ' + data.routes[0].legs[0].distance.text);
    }
    
  3. 创建一个 JavaScript 函数,使用 Google Maps API 请求路线:

    function checkDistance(sStart, sEnd) {
      $.ajax({
        type: 'GET',
        url: 'https://maps.googleapis.com/maps/api/directions/json?',
        data: { origin: sStart,
            destination: sEnd,
            sensor: 'true',
            units: 'metric',
            key: '<API key>' },
    
  4. 请记住,用 Google 提供的服务器应用的密钥替换<API key>,该密钥用于方向 API:

            success : retrieveDistance,
            error : function (request, status, message) {
            console.log('Error: ' + message);
            }
        });
    }
    
  5. 执行checkDistance()函数,并将起点和终点作为参数提供,例如:

    checkDistance('Plovdiv', 'Burgas');
    

地理坐标也可以作为参数传递给checkDistance()函数。例如,下面我们通过提供保加利亚城市普罗夫迪夫和布尔加斯的经纬度来计算相同的距离:

checkDistance('42.135408,24.74529', '42.504793,27.462636');

它是如何工作的

checkDistance()函数将数据发送到 Google Directions API。它将起点、终点、传感器、单位系统和 API 密钥作为 URL 的参数。API 返回的结果以 JSON 格式提供,并在retrieveDistance()函数中处理。

上一个示例的输出,在控制台中显示计算保加利亚城市普罗夫迪夫和布尔加斯之间的距离为普罗夫迪夫(保加利亚)和布尔加斯(保加利亚)之间的距离是:253 公里。

参见

检测设备运动

本教程介绍了如何在 Tizen Web 应用程序中检测和处理设备运动。不会使用特定的 Tizen API。本教程中的源代码依赖于标准的 W3C DeviceMotionEvent,该事件在 Tizen Web 应用程序以及任何现代 Web 浏览器中均得到支持。

如何操作

请按照以下步骤在 Tizen Web 应用程序中检测设备运动并显示其加速度:

  1. 创建一些 HTML 组件来显示设备加速度,例如:

    <p>X: <span id="labelX"></span></p>
    <p>Y: <span id="labelY"></span></p>
    <p>Z: <span id="labelZ"></span></p>
    
  2. 创建一个 JavaScript 函数来处理错误:

    function showError(err) {
      console.log('Error: ' + err.message);
    }
    
  3. 创建一个 JavaScript 函数,处理运动事件:

    function motionDetected(event) {
      var acc = event.accelerationIncludingGravity;
      var sDeviceX = (acc.x) ? acc.x.toFixed(2) : '?';
      var sDeviceY = (acc.y) ? acc.y.toFixed(2) : '?';
      var sDeviceZ = (acc.z) ? acc.z.toFixed(2) : '?';
    
      $('#labelX').text(sDeviceX);
      $('#labelY').text(sDeviceY);
      $('#labelZ').text(sDeviceZ);
    }
    
  4. 创建一个 JavaScript 函数,开始监听运动事件:

    function deviceMotion() {
      try {
        if (!window.DeviceMotionEvent) {
          throw new Error('device motion not supported.');
        }
        window.addEventListener('devicemotion', motionDetected, false);
      } catch (err) {
        showError(err);
      }
    }
    
  5. 在应用程序源代码的适当位置调用一个函数:

    deviceMotion();
    

它是如何工作的

deviceMotion() 函数注册一个事件监听器,当设备运动事件被检测到时,它会调用 motionDetected() 函数作为回调。所有错误,包括 DeviceMotionEvent 不被支持的错误,都会在 showError() 函数中处理。如下面的截图所示,motionDetected() 函数将 DeviceMotionEvent 属性的数据加载到在第一步中创建的 HTML5 标签中。结果使用国际单位制 (SI) 标准单位——每秒平方米(m/s²)来显示加速度。JavaScript 方法 toFixed() 被调用,将结果转换为一个包含两位小数的字符串:

工作原理

一个能够检测设备运动的 Tizen web 应用

另见

  • 请注意,设备运动事件规范是 DeviceOrientationEvent 规范的一部分,两者仍处于草案阶段。最新发布的版本可以在 www.w3.org/TR/orientation-event/ 查阅。

  • 本书提供了一个示例 Tizen web 应用的源代码,该应用能够检测设备运动。你可以将应用的项目导入 Tizen IDE 并进行探索。

检测设备方向

在这个实例中,你将学习如何使用 HTML5 DeviceOrientation 事件监控设备方向的变化,并通过 Tizen SystemInfo API 获取设备方向。这两种获取设备方向的方法都有其优点,并且都可以在 Tizen web 应用中使用。开发者可以根据自己的应用选择更合适的方法。

如何实现...

执行以下步骤以在 Tizen web 应用中注册监听器并处理设备方向事件:

  1. 创建一个 JavaScript 函数来处理错误:

    function showError(err) {
      console.log('Error: ' + err.message);
    }
    
  2. 创建一个 JavaScript 函数来处理方向的变化:

    function orientationDetected(event) {
      console.log('absolute: ' + event.absolute);
      console.log('alpha: ' + event.alpha);
      console.log('beta: ' + event.beta);
      console.log('gamma: ' + event.gamma);
    }
    
  3. 创建一个 JavaScript 函数,添加设备方向的监听器:

    function deviceOrientation() {
      try {
        if (!window.DeviceOrientationEvent) {
          throw new Error('device motion not supported.');
        }
        window.addEventListener('deviceorientation', orientationDetected, false);
      } catch (err) {
        showError(err);
      }
    }
    
  4. 执行 JavaScript 函数以开始监听设备方向事件:

    deviceOrientation();
    

工作原理

如果支持 DeviceOrientationEventdeviceOrientation() 函数会将事件绑定到 orientationDetected() 函数,只有在成功时才会作为回调被调用。showError() 函数只有在出现问题时才会执行。

DeviceOrientationEvent 接口的实例作为参数传递给 orientationDetected() 函数。在前面的代码片段中,它的四个只读属性的值:absolute(一个布尔值,如果设备提供绝对方向数据,则为 true),alpha(围绕 z 轴的运动),beta(围绕 x 轴的运动)和 gamma(围绕 y 轴的运动)会在控制台中打印出来。

还有更多...

有一种更简单的方法可以判断 Tizen 设备是处于横屏还是竖屏模式。在 Tizen web 应用中,建议在这种情况下使用 SystemInfo API。

以下代码片段获取设备的方向:

function onSuccessCallback(orientation) {
  console.log("Device orientation: " + orientation.status);
}

function onErrorCallback(error) {
  console.log("Error: " + error.message);
}

tizen.systeminfo.getPropertyValue("DEVICE_ORIENTATION", onSuccessCallback, onErrorCallback);

方向的状态可以是以下几种值之一:

  • PORTRAIT_PRIMARY

  • PORTRAIT_SECONDARY

  • LANDSCAPE_PRIMARY

  • LANDSCAPE_SECONDARY

另见

使用振动 API

Tizen 以其对 HTML5 和 W3C API 的卓越支持而闻名。标准振动 API 也得到了支持,并且可以在 Tizen 网页应用程序中使用。本篇提供了如何在 Tizen 设备上激活振动的代码片段。

如何操作...

  1. 使用以下代码片段可以激活设备的振动,持续 3 秒:

    if (navigator.vibrate) {
      navigator.vibrate(3000);
    }
    
  2. 若要取消正在进行的振动,只需再次调用 vibrate() 方法,并将其参数值设为零:

    if (navigator.vibrate) {
      navigator.vibrate(0);
    }
    
  3. 或者,通过传递一个空数组给相同的方法,可以取消振动:

    navigator.vibrate([]);
    

工作原理

W3C 振动 API 是通过 JavaScript 对象 navigator 使用的。其 vibrate() 方法期望接收单个值或值的数组。所有值必须以毫秒为单位指定。前面示例中传递给 vibrate() 方法的值为 3000,因为 3 秒等于 3000 毫秒。

还有更多...

W3C 振动 API 允许对设备的振动进行高级调节。可以通过 vibrate() 方法的参数指定一个时间间隔列表(单位为毫秒),在这些时间内设备将会振动。例如,以下代码片段将使设备振动 100 毫秒,静止 3 秒钟,然后再次振动,但这次仅为 50 毫秒:

if (navigator.vibrate) {
  navigator.vibrate([100, 3000, 50]);
}

另见

第三部分. 移植与调试

将应用移植到 Tizen

在 Tizen 中调试应用

将 Tizen 移植到硬件设备

第十章. 将应用移植到 Tizen

在本章中,我们将涵盖以下主题:

  • 移植 web 应用

  • 安装 PhoneGap 或 Cordova SDK

  • 使用 PhoneGap 或 Cordova 创建 Tizen web 应用

  • 将 Cordova 和 PhoneGap 应用部署到 Tizen 设备或模拟器

  • 将 Android 应用带到 Tizen

  • 将 Android UI 移植到 Tizen UI 框架

  • 为 Tizen 设置 Qt

  • 在 Tizen 上部署 Qt 应用

介绍

本章提供了将现有的 Web(Firefox OS、Chrome OS、webOS 等)、Android 或 Qt 应用移植到 Tizen 的选项和提示。教程包括如何使用兼容性层在 Tizen 上运行 Android 应用以及如何将 Android 应用完全移植到 HTML5。

本章还将介绍社区移植的 Qt for Tizen,它允许将现有的 Qt 移动应用程序部署到 Android、iOS、MeeGo/Harmattan、Symbian、SailfishOS 和 BlackBerry 10 设备上。

Tizen 是领先开发工具厂商(如 Marmalade、Appcelerator Titanium、Intel XDK、Project Anarchy、Sencha Touch 等)支持的平台之一。这些厂商提供的工具和技术简化了开发过程,并支持跨平台兼容性。关于 Tizen 合作伙伴工具的最新信息,请访问 www.tizen.org/about/partner-tools

移植 web 应用

Web 应用在 Tizen 中是一级公民,同样在 Firefox OS、webOS、Chrome 和 BlackBerry 10 等多个流行的移动平台上也具有重要地位。虽然需要明确的是,在 BlackBerry 10 上,本地应用是使用 C++ 和 Qt/QML 创建的。尽管如此,BlackBerry WebWorks 仍然提供了所有必要的工具,用于在 BlackBerry 10 设备上开发和部署具有原生外观和感觉的 HTML5 应用。

另一方面,Android 和 iOS 并未提供用于通过应用商店分发 HTML5 应用的通用工具。可以使用 Cordova 或 PhoneGap 等第三方软件来创建混合应用,并将 HTML5 项目部署为 Android 和 iOS(iPhone,iPad)设备上的独立应用。

根据技术和开发工具的不同,我们可以将移动设备上的 web 应用分为三类:打包 web 应用、托管 web 应用和混合 web 应用。

本教程的主要重点是托管的 Web 应用程序。我们将讨论当一个为其他平台构建的 HTML5 应用移植到 Tizen 时,最常见的挑战。在接下来的两个教程中,您可以详细了解将混合(Cordova 和 PhoneGap)Web 应用移植到 Tizen 的过程。

准备就绪

在开始将 Web 应用移植到 Tizen 之前,请花些时间查看您现有应用的结构和源代码。开始时的良好分析可以节省大量时间,并帮助您在移植过程中轻松解决问题。

正如您所知道的,Tizen Web 应用安装包的扩展名为 wgt。不同平台有不同的包格式和文件扩展名,具体见下表:

  • xpi 用于 Mozilla 的 FirefoxOS

  • crx 用于 Google 的 Chrome OS

  • ipk 用于 webOS

  • bar 用于 BlackBerry 10

  • xap 用于 Windows Phone 的 Web 应用

每个 Tizen Web 应用都有两个必需的组件:一个配置文件和一个主文件(index.html)。可选地,还可以设置图标,推荐的文件名为 icon``.``png,以及以下目录:

  • js 用于字符串 JavaScript 文件

  • css 用于存储 CSS 文件

  • img 用于存储图片

配置在 XML 文件中描述,该文件必须命名为 config.xml。可以在配置文件中设置所有可选资源的自定义名称。

如果您使用的是 Cordova 或 PhoneGap,您不需要担心,因为这些工具会在启用 Tizen 支持时自动生成适当的打包结构。否则,请查看您现有应用程序的结构,并找到相应的文件。您可能需要手动修改它们,以满足打包 Tizen Web 应用的要求。

如何操作...

以下指南指定了将现有独立 Web 应用移植到 Tizen 的必需操作:

  1. 创建一个 config.xml 文件并设置所有设置以及应用程序在 Tizen 设备上运行所需的任何权限。

    注意

    如果您正在将应用从 Firefox OS 移植,则 config.xml 相当于 manifest.webapp。Chrome 应用的配置文件名称为 manifest.json。在 webOS 上为 appinfo.json,Windows Phone 应用为 package.appxmanifest,BlackBerry WebWorks 应用为 config.xml

  2. 如果您的应用程序与服务器通信,请在配置文件中指定其域名。例如,以下设置允许 Tizen Web 应用访问 www.google.com

    <access origin="http://google.com" subdomains="true"></access>
    

    尽管不推荐,但出于安全原因,您也可以通过添加以下行来允许访问任何服务器:

    <access origin="*" subdomains="true"></access>
    
  3. config.xml 中添加您的应用程序所需的任何权限。

  4. 按照 Tizen 图标指南 developer.tizen.org/documentation/ux-guide/visual-style/icons 创建一个图标。

  5. 在 Tizen 设备或模拟器上构建并运行你的应用程序。请记住,用户界面中可能会出现不一致的行为和错误。请仔细测试应用程序。你可能需要调试并调整 HTML、CSS 和 JavaScript 文件。

另见

  • 一般来说,强烈建议仅依赖平台文档中的 HTML5 规范。然而,在某些情况下,尤其是对于托管 Web 应用程序,你可能会觉得比较不同平台及其浏览器的 HTML5 规范有用,具体可以参考 html5test.com/

安装 PhoneGap 或 Cordova SDK

PhoneGap 和 Cordova 是用于开发跨平台 HTML5 移动应用程序的流行工具。其主要优点是通过单一的代码库即可面向多个移动平台。所有最流行的移动操作系统都受到支持:Android、iOS、Windows Phone、BlackBerry 10,当然还有 Tizen。即使是如今不再流行的老旧平台,如 Symbian 和 webOS,也受到支持。

此外,PhoneGap 和 Cordova 允许 Web 开发人员利用他们现有的知识,开发高质量的移动应用程序,而无需学习 Java、Objective C 或 C++。

Cordova 和 PhoneGap 都是开源项目。Cordova 在 Apache 2.0 许可下发布。PhoneGap 是 Cordova 的一个分支,自 2011 年起,由 Adobe 拥有和维护。因此,有时 Cordova 被称为 PhoneGap 背后的引擎,或作为 Adobe 发行版的 Cordova。

使用 PhoneGap 和 Cordova 的移动应用程序开发人员将其捆绑为标准安装包,这些安装包会部署到移动设备上。例如,Android 的安装文件扩展名为 .apk,而 Tizen 的扩展名为 .wgt

在本食谱中,你将学习如何安装 PhoneGap 或 Cordova,在随后的食谱中,你将学习如何为 Tizen 设置和部署应用程序。

准备工作

确保你已经按照第一章中的说明成功安装了 Tizen SDK。PhoneGap 和 Cordova 都依赖其工具来为 Tizen 构建和打包应用程序。在继续之前,还需要确保你已经安装了npm(Node 包管理器)。

如果你使用的是 Ubuntu,请运行以下命令添加 Cordova 的软件库,并确保所有软件库的信息是最新的:

sudo apt-add-repository ppa:cordova-ubuntu/ppa 
sudo apt-get update 
sudo apt-get install cordova-cli

如何做...

安装 Cordova 和 PhoneGap 非常简单。打开终端并执行以下命令来安装最新版本的 Cordova:

npm install -g cordovaRun the command below to install the latest version of PhoneGap:
npm install -g phonegap

正如你可能已经注意到的,两个命令都包含一个参数-g。它指定这是一个全局安装。

它是如何工作的

Cordova 和 PhoneGap 的安装是通过 Node 包管理器完成的,Node 包管理器是用于管理 Node.js 包的软件。它完全使用 JavaScript 和 Node.js 平台编写。

注意

Node.js 和 npm 是开源项目。Node.js 在 MIT 许可证下提供,但它与其他开源许可证下的组件一起捆绑提供。Node 包管理器的源代码可以在 Apache 许可证 2.0 下获取。

另请参阅

  • 以下食谱提供了如何将 PhoneGap 和/或 Cordova 与 Tizen SDK 集成的说明,并介绍了如何创建和部署应用程序到 Tizen。

使用 PhoneGap 或 Cordova 创建 Tizen Web 应用程序

在本食谱中,您将学习如何通过 Tizen IDE 使用 PhoneGap 和 Cordova 创建 Tizen 的 Web 应用程序。

准备工作

请确保您已经安装了 Tizen SDK 以及 Cordova 或 PhoneGap。有关 Tizen SDK 安装的说明请参见本书的第一章。关于设置 Cordova 和 PhoneGap 的教程,请参考之前的食谱。

Cordova 和 PhoneGap 版本 3.5 或更早的版本不支持 Tizen 的命令行界面(CLI)。通过 Cordova 和 PhoneGap 提供的一些示例应用程序被用作模板来创建 Tizen 项目。请确保您在计算机上拥有这些示例。您可以从 Apache 公共 Git 服务器获取它们的最新版本。输入以下命令将它们克隆到您的计算机上:

git clone git://git.apache.org/cordova-tizen.git

如何操作...

按照以下步骤,使用 Tizen IDE 为 Tizen 创建 Cordova 或 PhoneGap 应用程序:

  1. 启动 Tizen IDE。

  2. 导航到 文件 | 导入 | Tizen Web 项目,然后点击 下一步

  3. 点击 浏览... 浏览示例 Cordova 项目的根目录。

  4. 选择 将项目复制到工作区如何操作...

    将 Cordova 示例应用程序导入 Tizen IDE

  5. 点击 完成

工作原理

Cordova 和 PhoneGap 等项目的主要目的是提供易于使用的工具,以使用 Web 技术 HTML、CSS 和 JavaScript 开发移动应用程序。Web 应用程序是 Tizen 中的第一类公民,因此它是一个非常适合 Cordova 和 PhoneGap 项目的平台。

Tizen IDE 可以直接用于导入、开发、调试和部署 Cordova 或 PhoneGap 应用程序。在前面教程的第三步中,示例 Cordova 应用程序被用作模板。重要的是要确保在第四步中所述的 将项目复制到工作区 选项已被勾选。IDE 将复制该应用程序并将其保存在当前工作区。

另请参阅

将 Cordova 和 PhoneGap 应用程序部署到 Tizen 设备或模拟器

在 Tizen IDE 工作空间中创建或导入新的或现有的 Cordova/PhoneGap 应用程序后,是时候部署它了。在本配方中,你将学习如何使用 Tizen IDE 的选项将 Cordova 或 PhoneGap 应用程序部署到 Tizen 设备或模拟器。

准备工作

我首选的在 Android 设备或模拟器上构建和部署 Cordova 应用程序的方法是通过控制台输入以下命令:

Cordova run android

不幸的是,在写这本书时,Tizen 的命令行界面(CLI)在 PhoneGap 和 Cordova 中都不可用。如你所见,考虑到这些情况,开发和部署 Cordova 或 PhoneGap 应用程序到 Tizen 设备或模拟器的最简单方法是通过 IDE 的用户界面。

在继续之前,确保你已将 Tizen 设备连接到计算机,或者在计算机上启动了 Tizen 模拟器。

如何操作...

按照这些简单的指示,将 Cordova 或 PhoneGap 应用程序部署并运行在 Tizen 模拟器上:

  1. 在 Tizen IDE 中导航到 项目资源管理器 视图。

  2. 右键点击项目。

  3. 导航至 以此方式运行 | Tizen Web 模拟器应用程序

在真实设备上部署应用程序的过程几乎相同。确保 Tizen 设备已成功连接到计算机,然后执行以下操作以运行应用程序:

  1. 在 Tizen IDE 中导航到 项目资源管理器 视图。

  2. 在项目上右键点击鼠标右键。

  3. 导航至 以此方式运行 | Tizen Web 应用程序

工作原理

Tizen IDE 适合手动操作,但如果你想创建持续集成并测试使用 Cordova 和 PhoneGap 创建的 Tizen Web 应用程序,它可能会成为障碍。Tizen IDE 依赖于以 Tizen 为中心的工具,如 SDB 来部署应用程序。在极少数情况下,当你需要通过控制台而不是输入 cordova run 来部署应用程序时,使用 sdb install,然后输入应用程序 wgt 文件的完整名称。

另见

  • 如果你正在寻找如何通过控制台将 Cordova 或 PhoneGap 应用程序部署到 Tizen 设备和模拟器的选项,请参阅本书第一章中的 Smart Development Bridge 配方,以了解更多关于 SDB 使用的细节。

将 Android 应用程序移植到 Tizen

Tizen 智能手机的功能和硬件按钮与安卓设备相似。由三星制造的 Tizen 智能手机的用户界面与 TouchWiz 相似——这是现有三星安卓设备的前端触摸界面。

安卓已经在智能手机市场占据主导地位多年,数以百万计的安卓应用存在。像 BlackBerry 10 和 SailfishOS 这样的替代平台提供了运行安卓应用的运行时环境。相同的方式也能让我们在 Tizen 上运行安卓应用。Tizen 生态系统中最流行的解决方案是 OpenMobile 提供的应用兼容层ACL)。在本教程中,将揭示开始使用 ACL 所需的基本步骤。

准备就绪

请准备好您的安卓应用的APK(应用程序包文件)。如果您计划提交付费应用,请确保您拥有有效的银行账户或 PayPal 账户。

如何操作...

按照以下说明注册 OpenMobile 开发者计划,并通过他们的服务将您的安卓应用移植到 Tizen:

  1. 访问 OpenMobile 网站并注册成为 AppMall 内容提供商:www.openmobileww.com/#!content-provider-registration/cuwc

  2. 您将在 24 小时内收到包含用户名和密码的电子邮件。

  3. 收到电子邮件后,登录到manager.openmobileappmall.com

  4. 点击个人资料表单,输入您偏好的支付方式。支持通过 PayPal 和银行转账进行支付。

  5. 进入我的应用并点击添加应用如何操作...

    向 OpenMobile AppMall 添加新应用

  6. 概述标签页中填写所有详细信息。

  7. 进入版本 / 文件标签页,上传您的安卓应用程序:如何操作...

    上传 APK 文件

它是如何工作的

OpenMobile 的应用兼容层基于 Google 的Android 开源项目AOSP)。基于此,ACL 集成了安卓应用的图形堆栈、媒体、进程间通信IPC)和通知系统与 Tizen 的兼容性。通过使用 ACL,安卓应用可以像其他 Tizen 的网页或本地应用一样从 Tizen 桌面启动。与其他应用一样,Tizen 上的安卓应用也会显示在操作系统的任务管理器中。

OpenMobile 会将您的apk转换为tpk,进行验证,并发布到 Tizen 商店。OpenMobile 还会对tpk进行签名,并在 Tizen 商店卖家办公室处理应用程序的全部管理工作。应用下载报告以及收入将定期与开发者共享。

参见

将 Android UI 移植到 Tizen UI 框架

本文提供的信息在你决定将 Android 应用移植到 Tizen Web 应用时会非常有用。请注意,由于你需要将 Java 代码重写为 HTML5 和 JavaScript,因此需要大量开发工作。本章概述并比较了 Android 和 Tizen 组件,应该是计划移植 Android 应用程序的开发人员的一个良好起点。

如何操作...

将使用 Android SDK 开发的应用完全移植到 HTML5 需要大量的工作,必须执行以下操作:

  1. 完全使用 HTML5 重写用户界面。

  2. 将现有的 Java 源代码移植到 JavaScript。

在 Tizen 设备或模拟器上构建和调试应用。以下是 Android UI 组件(来自 Java 包 android.widget)的常见组件列表,以及如何在 Tizen Web 应用中使用 Tizen Web UI Framework 替代它们的简要说明:

  • Button:Tizen Web UI Framework 提供了一个同名且具有相同行为的组件。创建它有几种方法。以下是使用 a 元素和 data-role="button" 的一种方法:

    <a id="myBtn" href="#" data-role="button">Button 1</a>
    
  • EditText:这是一个可编辑的文本框。在 Tizen Web 应用中,收集用户信息时可以通过文本输入字段获得相同的用户体验,例如:

    <div data-role="fieldcontain">
      <label for="name">Text:</label>
      <input type="text" name="txt" id="txt" value=""  />
    </div>
    
  • CheckBox:Tizen UI 框架和 jQuery Mobile 都提供了 Checkbox 组件,可以在 HTML5 应用中替代 Android 组件。

  • ToggleButton:这种按钮允许用户快速在两种状态之间切换。请注意,只允许两种状态。Tizen Web UI Framework 提供了一个相同功能的组件——Flip Toggle Switch。它可以通过以下代码片段创建:

    <select id="SwitchBtn" data-role="slider">
      <option value="off">Off</option>
      <option value="on">On</option>
    </select>
    
  • Spinner:这个 Java 类提供了一个组件,用于在 Android 中快速从列表中选择一个值。在 HTML5 应用中,可以用 select 组件和多个选项来替代它。

  • DatePickerTimePicker:Tizen Web UI Framework 提供了以下组件,用于收集用户关于日期和时间的输入:日期选择器、时间选择器和日期时间选择器。例如,Tizen 的日期选择组件可以通过以下 HTML 实现:

    <div>
      <input type="date" name="datePicker" id="datePicker" data-format="dd MMM yyyy" />
    </div>
    

    如何操作...

    一个带有日期选择器的示例 Tizen Web 应用

  • Toast:在 Android 中,这个组件用于向用户展示消息,以小弹窗的形式,不需要任何交互。在 Tizen Web 应用程序中,可以用 Notification 组件来替代它。

  • AlertDialog:这个弹出组件应该在 Tizen Web 应用程序中用来替代 Android 中的 AlertDialog。使用带有属性 data-role="popup"div 元素来创建它。

它是如何工作的

在使用 HTML 创建用户界面后,你需要重写应用程序的逻辑。以下是一个对比,展示了在 Android 应用中处理按钮点击的 Java 代码片段与在 Tizen Web 应用中处理相同用例的 JavaScript 代码。

来自 Android 应用的示例 Java 源代码处理 ID 为 myBtn 的按钮点击事件:

final Button button = (Button) findViewById(R.id.myBtn);
button.setOnClickListener(new View.OnClickListener() {
  public void onClick(View v) {
    //do something
  }
});

以下 JavaScript 代码处理 ID 为 myBtn 的按钮的 click 事件:

$('#myBtn').bind( "click", function(event, ui) {
  //do something
});

如你所见,概念是相同的,但由于 Java 和 JavaScript 编程语言的特性,语法上有很大的差异。在这两种情况下,按钮的 ID 都是 myBtn,从用户的角度看,点击 Tizen Web 应用中的按钮与点击 Android 应用中的按钮效果是一样的。

另见

设置 Qt for Tizen

Qt 是一个流行的跨平台应用程序开发框架,主要用于开发迷人的图形用户界面。主要的编程语言是 C++ 和 QML,但通过语言绑定也可以使用其他编程语言,如 Python。

Qt 项目有着悠久的历史。它的开发始于 1991 年的瑞典,直到 2008 年,该框架由 Trolltech 开发。之后,诺基亚收购了 Qt。最初,Qt 仅提供商业和 GPL 许可。2009 年,Qt 也开始提供 LGPL 许可。两年后,诺基亚将 Qt 的商业许可业务出售给了 Digia。

项目的最新主要版本是 Qt 5,它于 2012 年底发布。一年后,Tomasz Olszak 和 Jarosław Staniek 创建了一个开源项目,旨在将 Qt 5 移植到 Tizen。我很自豪,作为本书的评审,Philippe Coval 和我也是该项目的首批贡献者之一,我们能够帮助项目的主要开发者 Tomasz Olszak 在不同的参考设备上进行 Qt for Tizen 的测试以及代码审查。

本教程中,你将学习如何安装和配置开发环境,以便为 Tizen 移动设备构建 Qt 应用程序。

准备工作

本教程仅在 Ubuntu 上进行过测试。在继续下一个部分之前,请确保你已经满足以下四个要求。

  • 确保你已成功安装 Tizen SDK。设置 Qt for Tizen 需要从源代码构建 Qt,并安装 Qt Creator,因此请确保至少有 5 GB 的空闲磁盘空间。

  • 运行 apt-get 并确保安装了以下长列表中的所有软件包,因为它们是构建 Qt 所需的:

    sudo apt-get install perl python git build-essential libqt4-dev "^libxcb.*" libx11-xcb-dev libxkbcommon-dev libglu1-mesa-dev libxrender-dev libdbus-1-dev libfontconfig1-dev libfreetype6-dev libatspi2.0-dev flex bison gperf libicu-dev libcups2-dev libxslt-dev ruby libsqlite3-dev libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev libssl-dev libpulse-dev libasound2-dev libgtk2.0-dev libpng12-dev libjpeg8-dev libjpeg-dev chrpath
    
  • 安装 GBS。首先,应该将与您的发行版对应的 Tizen 仓库添加到 /etc/apt/sources.list。然后,运行以下命令:

    sudo apt-get update
    sudo apt-get install gbs
    

    注意

    有关 Tizen 开发工具的最新安装指南,请访问 source.tizen.org/documentation/developer-guide/getting-started-guide/installing-development-tools

  • 确保你有有效的作者证书。请参考第一章中的配方 设置活动安全配置文件 获取更多细节。

如何操作...

以下说明将解释如何安装 Tizen 开发工具、从源代码构建 Qt、安装 Qt Creator,并为其设置 Tizen 插件。

  1. 创建一个目录来存储 Qt 的源代码。

  2. 通过从项目的 Git 仓库克隆源代码,将源代码下载到计算机:

    git clone -b alpha6 git://gitorious.org/tizenbuildtools/tizenbuildtools.git
    cd tizenbuildtools
    git checkout v_alpha6.2
    
  3. 进入桌面目录并构建 Qt:

    cd desktop
    MAKE_THREADS=4 ./downloadAndBuildAll.sh
    

    注意

    将线程数替换为与处理器核心数量相匹配的数字。

    或者,你可以使用以下命令,这些命令会自动获取核心数量:

    MAX_THREAD=$(grep 'Core' /proc/cpuinfo | wc -l ) ./downloadAndBuildAll.sh

  4. 进入 emulator 目录,准备 Tizen 的 Qt 模拟器:

    cd ../emulator
    ./prepare_developer_tools.sh
    
  5. 再次更改当前目录,这次进入 mobile 目录。准备 Qt 使 Tizen 在设备上运行:

    cd ../mobile
    ./prepare_developer_tools.sh
    
  6. 访问 qt-project.org/downloads#qt-creator 并下载 Qt Creator。

  7. 安装 Qt Creator。在 Linux 上,可以通过命令行使用以下命令启动安装:

    chmod u+x ./qt-creator-linux-...run
    ./qt-creator-linux-...run
    
  8. 构建 Qt Creator 的 Tizen 插件:

    cd ../qtcreator
    export PATH=$HOME/dev/src/tizenbuildtools/desktop/qt5hostInstall/bin:$PATH
    QTC_BUILD=$HOME/qtcreator-3.0.1 ./build_and_deploy_tizen_plugin.sh
    

还有更多...

按照以下步骤将 Tizen SDK 集成到 Qt Creator 中:

  1. 启动 Tizen 模拟器管理器

  2. 启动 Qt Creator。

  3. 导航到 工具 | 选项

  4. 选择 Tizen

  5. 导航到 Tizen SDK 路径,点击 浏览 查找 Tizen SDK 安装目录,然后点击 确定

  6. 导航到 作者证书,然后再次点击 浏览 以选择证书。在 Linux 上,作者证书的默认存储路径为 $HOME/tizen-sdk-data/keystore/author/

  7. 输入证书的密码。

几乎完成了。现在,你需要为 Qt Creator 配置 Tizen 模拟器:

  1. 选项 对话框中,进入 设备,选择 tizen

  2. 输入一个名称,方便将来区分这就是 Tizen 模拟器。

  3. 选项 进入 构建与运行,选择 Qt 版本 标签并点击 添加

  4. 选择 qmake 用于 Tizen 模拟器构建,并点击 应用。默认路径应为 $HOME/dev/src/tizenbuildtools/emulator/qt5CrossCompileTools/bin/qmake

  5. 转到 工具 标签,点击 添加,并输入适当的名称,例如 Tizen 模拟器

  6. 点击 添加

  7. 选择 Tizen 设备 作为 设备类型,选择 Tizen GCC (x86) 作为 编译器,并在 Qt 版本 字段中选择用于模拟器的 Qt 版本。

  8. 点击 应用

另见

在 Tizen 上部署 Qt 应用程序

这个食谱将解释如何在 Tizen 模拟器或设备上准备、构建和部署 Qt 应用程序。

准备工作

在开始之前,确保你已经在计算机上成功设置了 Qt for Tizen。正如我们在书籍开头讨论的那样,Tizen 智能手机既支持使用 C++ 创建的原生应用程序及其 .tpk 扩展,也支持使用 .wgt 扩展的 Web 应用程序。Qt 是一个基于 C++ 的框架,因此 Tizen 的移植依赖于 .tpk 文件的工具。

如何实现…

按照这些逐步说明使用 Qt Creator 开发新的或移植现有的 Qt 应用程序到 Tizen:

  1. 在 Qt 应用程序项目中创建一个名为 tizen 的目录。

  2. helloworld 项目中的 manifest.xml 文件(该项目与 qtquickcontrols-tizen 一同提供)复制到你在上一步中创建的目录中。

  3. 编辑manifest.xml并在其中设置应用程序 ID。

  4. 打开应用程序的 .pro 文件,通过添加以下规则来启用 Tizen 支持:

    tizen {
      tizen_shared.files = shared/res
      CONFIG += TIZEN_STANDALONE_PACKAGE
      TIZEN_BUNDLED_QT_LIBS=Qt5Core Qt5DBus Qt5Qml Qt5Quick Qt5Widgets Qt5Gui Qt5Network
      load(tizen_app)
    }
    
  5. 打开main.cpp并实现以下源代码,为 OspMain() 方法编写代码,这是 Tizen 原生应用程序的入口点:

    extern "C" int OspMain(int argc, char *argv[]) {
      return main(argc, argv);
    }
    

    注意

    这个食谱已经在 Tizen 移动配置文件上进行了测试。它不能在 Tizen IVI 或其他不支持原生应用程序开发的配置文件上使用。

  6. 构建应用程序,并通过 Qt Creator 将其部署到 Tizen 模拟器或设备上。

它是如何工作的

提供的 helloworld 应用程序(与 qtquickcontrols-tizen 一起提供)作为模板使用。实际上,这个食谱的第一步几乎与使用 Cordova 或 PhoneGap 创建 Tizen 应用程序的第一步相同。尽管这些技术创建的是 Web 应用程序,但它们的第一步是导入并使用一个示例应用程序作为模板。

第二步和第三步专注于manifest.xml。这是一个配置文件。每个 Tizen 原生应用程序必须有一个符合 XML 标准的单一 manifest 文件。

下一步仍然是编辑配置文件。.pro 扩展名是 Qt 应用程序项目文件的特定扩展名。此文件必须包含 qmake 构建应用程序所需的所有信息。

在第五步中,作为 Tizen 原生应用程序入口点的方法被指示运行 Qt 应用程序的主方法。传递给 OspMain() 的所有参数都被传递给 main()OspMain() 的前缀代表开放服务平台(Open Service Platform),其来源可追溯至与 Tizen 2 合并的 Bada。

另见

第十一章:在 Tizen 中调试应用程序

本章将涵盖以下主题:

  • 在 Tizen Web 模拟器中运行应用程序

  • 在 Tizen 模拟器中运行应用程序

  • 在设备上运行应用程序

  • 在 Tizen Web 模拟器中调试

  • 在 Tizen 模拟器中调试

  • 在设备上调试

  • 使用三星远程测试实验室

  • 跟踪 JavaScript 错误

  • 使用 QUnit 进行单元测试

介绍

质量保证是应用程序开发过程中最重要的流程之一,因为它确保减少问题并为最终用户提供更好的体验。许多优秀的移动应用程序因存在缺陷而未能取得商业成功。即使一款应用具有出色的用户界面并提供良好的用户体验,仍然不足以确保它会成功。

一般来说,用户对错误的容忍度很低。如果应用程序崩溃一次,用户可能再也不会打开它。

本章的内容提供了如何测试应用程序并提供良好质量的思路和教程。在本章中,您将了解如何运行和调试 Tizen 应用程序,并探索 Web 应用程序的 JavaScript 单元测试。

本章还包括一个关于三星 远程测试实验室 (RTL) 的食谱,并提供了如何在远程物理 Tizen 设备上部署和测试应用程序的教程。尽管没有单独的食谱介绍 Selenium,您可以考虑使用该工具进行 Web 应用程序的功能性和用户验收测试,这些应用程序与 Tizen 兼容。欲开始使用该工具,请访问 www.seleniumhq.org/

在 Tizen Web 模拟器中运行应用程序

您应该已经熟悉第一章中介绍的 Tizen Web 模拟器,用于 Web 应用程序。在本食谱中,您将详细了解如何使用它。

准备工作

可以通过 Tizen IDE 在模拟器中启动 Tizen Web 应用程序。所有操作步骤已在本书的第一章中详细说明,以下是简要总结:

  • 项目资源管理器 视图中选择项目。右键点击项目以激活上下文菜单,并导航到 运行方式 | Tizen Web 模拟器应用程序

  • 转到 Tizen IDE 的 运行 菜单,导航到 运行方式 | Tizen Web 模拟器应用程序

  • 或者,直接点击 Tizen IDE 工具栏中的 运行 按钮。

如何操作...

可以配置模拟器的设备信息和系统设置。请按照以下说明配置模拟器:

  1. 使用三种可用选项之一启动模拟器。

  2. 点击模拟器右上角的 配置 按钮。

  3. 调整设备、系统和网络设置,如下图所示:如何操作...

    Tizen Web 模拟器的配置设置

此外,您还可以通过点击位于 配置 按钮旁边的 面板设置 按钮来调整可见面板。

还有更多内容

Tizen Web 模拟器提供了多个面板来模拟各种事件。以下是按出现顺序列出的可用面板:

  • 方向与缩放:此面板允许您将模拟器的方向从竖屏切换为横屏,反之亦然。作为附加功能,您还可以从同一面板调整缩放级别。

  • 系统摘要:此面板提供有关系统和应用程序的基本信息。

  • 通知:此面板显示接收到的通知列表。

  • 传感器:此面板对于模拟与加速度计和陀螺仪相关的事件非常有用。它提供了调整设备位置以及模拟器设置的选项。

  • 地理定位:此面板用于设置当前时区、位置和路线。它对于在模拟器中测试基于位置的 Tizen Web 应用程序非常有用,无需真实的 GPS 设备。

  • 应用配置:此面板显示有关应用程序配置及其安装包的信息。基本上,它显示的是 config.xml 文件的内容。

  • 通信:开发人员可以通过此面板模拟接听电话和处理消息,以及接收推送通知。

  • 电池管理:此面板可调整电池电量并模拟低电量状态。

  • 网络管理:此面板控制模拟器的网络单元:NFC、蓝牙、Wi-Fi 和蜂窝网络。

  • 下载:此面板管理模拟器的下载资源。

  • 包和应用:此面板显示模拟器上安装的包和应用程序的列表。此外,您可以通过此面板删除已安装的包或应用程序。

另请参阅

在 Tizen 模拟器中运行应用程序。

使用此方法,你将回顾如何启动 Tizen 模拟器,并学习如何运行应用程序以及如何使用事件注入器模拟事件。

如何操作...

有几种启动 Tizen 模拟器的选项。它们都已在本书的第一章中介绍过,并提供了如何创建虚拟 Tizen 设备的说明。在继续之前,请确保你已经设置了虚拟机。

从用户的角度来看,启动 Tizen 模拟器的最简单方法是使用模拟器管理器。以下是所需操作的快速回顾:

  1. 启动 Tizen 模拟器,它随着 Tizen SDK 的安装而提供。

  2. 选择所需的配置,并点击播放按钮启动它。

启动 Tizen 模拟器的另一种选择是,在终端中键入以下命令:

./emulator-x86 --skin-args <skin options> --qemu-args <QEMU options>

一旦模拟器启动,你可以直接从 Tizen IDE 安装并启动 Tizen 应用程序。有三种方法可以做到这一点,选择最适合你的方法:

  • 转到项目资源管理器视图,打开一个项目,右键点击该项目,选择运行方式 | Tizen Web 应用程序

  • 在 Tizen IDE 中,导航至运行菜单,并选择运行方式 | Tizen Web 应用程序

  • 点击 Tizen IDE 工具栏中的运行按钮。

在应用程序运行于模拟器时,你可以使用事件注入器模拟各种事件来测试它。以下事件可以通过 Tizen IDE 中的事件注入器视图或通过控制台创建并发送到模拟器:

  • 传感器:此事件指示与以下任一传感器相关的值:加速度、磁场、陀螺仪、接近或光线。

  • 运动:此事件模拟摇晃等运动事件。

  • 电池:此事件调整当前电池电量以及充电器的状态。

  • 耳机插孔:此事件控制耳机的状态。

  • USB:此事件管理虚拟设备的 USB 连接器状态。

  • RSSI(接收信号强度指示):此事件模拟不同的信号强度。请注意,如果将 RSSI 设置为0,则文本消息和呼叫事件将无法工作。

  • SD 卡:此事件设置 SD 卡指示器的状态。

  • 位置:此事件模拟设备的虚拟位置,用于测试目的。

  • 短信:此事件模拟发送短信。

  • 呼叫:此事件处理模拟呼叫。

  • NFC:此事件管理 NFC 标签,例如 NDEF 消息、NFC 标签等。

另见

在设备上运行应用程序

在本书的前几章中,我们已经讨论了 SDB 以及如何在模拟器或设备上运行应用程序。本节的目的是巩固这些知识。

准备就绪

执行以下操作以设置连接设备的运行配置:

  1. 确保 Tizen 设备已成功连接到计算机,并且可以在 Tizen IDE 的连接资源管理器中识别到该设备。

  2. 在首次启动应用程序之前,使用以下任一方法调整配置:

    • 从 Tizen IDE 的主菜单中选择运行 | 运行配置

    • 项目资源管理器视图中找到项目,右键点击该项目,在上下文菜单中选择以...运行 | 运行配置

如何操作...

确保你已经调整了运行配置,并使用以下任意方法将应用程序运行在连接的 Tizen 设备上:

  1. 导航到项目资源管理器视图,选中项目并右键点击它。将出现一个上下文菜单。选择以...运行 | Tizen Web 应用程序

  2. 在 Tizen IDE 菜单中,转到运行 | 以...运行 | Tizen Web 应用程序

  3. 点击 Tizen IDE 工具栏中的运行按钮。

无论你选择哪种方法,最终结果都会相同。使用最适合你的方法。

工作原理

在 Tizen 设备上运行应用程序的算法包括五个主要步骤。第一步是构建应用程序。之后,如果是 Web 应用程序,必须将其打包为.wgt,如果是原生应用程序,则打包为.tpk。第三步是将包传输到连接的设备。接下来的步骤是安装该包,最后在设备上启动应用程序。

另见

在 Tizen Web 模拟器中调试

本教程提供了使用 Web 模拟器及其 Web 检查器运行和调试 Tizen Web 应用程序的指南。

如何操作...

按照以下说明,在 Web 模拟器中运行 Tizen Web 应用程序并进行调试:

  1. 根据本教程《在模拟器中运行应用程序》中的任一方法启动模拟器中的应用程序。

  2. F12打开 Web 检查器。

  3. 点击Console查看日志信息。

  4. 点击Sources,选择一些 JavaScript,并设置和控制断点以调试应用程序。

它是如何工作的

Tizen Web 模拟器在 Google Chrome 浏览器中运行。当你从 Tizen IDE 启动它时,它会自动启动一个新的 Chrome 窗口并加载一个本地 URL。所有 Chrome 的调试工具都可以在模拟器中使用。

另见

在 Tizen 模拟器中调试

在本教程中,你将学习如何在模拟器上安装和运行 Tizen 应用程序的调试模式,并使用远程检查器进行调试。

准备工作

用于调试模拟器中应用程序的工具叫做远程检查器(Remote Inspector),它需要 Google Chrome 浏览器。请确保在开发用的电脑上已成功安装 Chrome,然后再继续操作。

如何操作...

按照以下步骤,使用模拟器调试 Tizen 应用程序:

  1. 启动 Tizen IDE 和 Tizen 模拟器。

  2. Project Explorer中选择应用程序,并使用以下任一方法将其启动到模拟器中:

    • 右键单击项目,选择Debug as | Tizen Web Application

    • 在 Tizen IDE 的工具箱中点击Debug按钮

    • 从 Tizen IDE 的菜单中选择Run | Debug As | Tizen Web Application

它是如何工作的

模拟器提供了完整的操作平台堆栈,方便测试 Tizen 本地应用和 Web 应用。它与 Tizen IDE 良好集成。应用程序会被复制到模拟器中,之后会自动安装并启动。一个新的 Chrome 窗口将为远程检查器打开。

另见

在设备上调试

在真实的 Tizen 设备上调试几乎与在模拟器上相同。本食谱仅会揭示在设备上执行过程时的细微差异。

准备工作

在真实设备上调试 Tizen 应用程序的要求与在模拟器上相同。必须在你的开发机器上安装 Google Chrome,因为远程检查器需要它。

如何操作……

按照以下说明,通过 Tizen IDE 安装和调试应用程序到 Tizen 设备:

  1. 启动 Tizen IDE。

  2. 连接设备,并确保设备在 Tizen IDE 的 Connection Explorer 中被识别并显示。

  3. 使用以下任一方法,在设备上以调试模式启动应用程序:

    • 右键单击项目,选择 Debug as | Tizen web application

    • 点击 Tizen IDE 工具箱中的 Debug 按钮

    • 从 Tizen IDE 的菜单中,导航至 Run | Debug As | Tizen Web Application

正如从前面的教程中看到的,步骤几乎与在 Tizen 模拟器上调试应用程序时相同。

还有更多内容

将应用程序构建、复制并安装到 Tizen 设备上可能是一个烦人的过程,尤其是每天需要做几百次。你想节省开发时间,加速调试过程吗?

Tizen 快速开发支持RDS)来拯救你!使用它,应用程序仅在首次运行时进行完整打包、复制并安装到设备上。之后,打包步骤将被跳过,只有修改过的文件才会被传输到设备。RDS 内置了看门狗功能,监控过程,如果出现失败,则会执行应用程序的正常安装。

默认情况下,RDS 是启用的。如果你需要禁用它,请前往 Tizen IDE 的 Windows 菜单,选择 Preferences | Tizen SDK | Rapid Development Support

更多内容

启用或禁用快速开发支持

另见

使用三星远程测试实验室

三星提供了一项免费的服务,允许在 Android 和 Tizen 系统的移动设备及可穿戴设备上进行应用程序的远程测试。这项服务被称为三星 远程测试实验室RTL)。它是一种方便且实惠的方式,可以在没有实际操作的情况下,在物理设备上试用应用程序。

准备工作

你需要是注册的三星开发者才能使用 RTL。如果你没有账户,可以在 developer.samsung.com/signup 上免费注册。

RTL 有一些技术要求,你必须满足:

  • 现代网页浏览器(Firefox v2+、Internet Explorer v7+、Opera v9.6+、Chrome 7+ 或 Safari v3+)

  • 在网页浏览器中启用 JavaScript

  • Java Web 启动

准备工作

远程测试实验室的要求

该服务可以在 GNU/Linux、Mac OS X 和 Microsoft Windows 的计算机上使用。你还应该准备好应用程序的安装文件。

如何操作...

按照以下分步指南,通过 RTL 访问 Tizen 设备并在其上启动你的应用程序:

  1. 使用你的三星开发者账户登录:account.samsung.com/account/check.do

  2. 访问三星远程测试实验室:developer.samsung.com/remotetestlab/rtlDeviceList.action

  3. 进入 Tizen 标签,选择设备、操作系统版本和预定时长。

  4. 点击 开始,等待 RTL 客户端加载。

  5. 右键点击 RTL 客户端的顶部,导航到 测试 | 安装应用程序,如下面的截图所示:如何操作...

    安装 Tizen 应用程序

  6. 上传你的应用程序安装文件并点击 安装

  7. 成功后,将显示以下消息:应用程序已成功安装

工作原理

RTL 客户端应用程序已安装在你的计算机上,并提供了一个环境和连接到物理 Tizen 设备的方式,可以远程使用。这些设备分布在世界各地:韩国、波兰、印度、英国、美国和俄罗斯。

如果有空闲设备,你可以立即使用它。或者,你也可以进行预定,稍后使用它。虽然该服务是免费的,但有一些限制,你需要积分才能使用设备。每个三星开发者每天获得 20 个积分。每个积分可以使用设备 15 分钟,最短预定时间为半小时(2 个积分)。

你应该将设备保持与发现时相同的状态,因此请记住你必须移除所有已安装的应用程序。你可以选择屏幕质量:普通。如果你的网络连接较慢,建议使用低质量。RTL 客户端还允许你通过其上下文菜单更改设备方向。其他有用的功能包括捕捉屏幕截图和录制视频。

另请参阅

追踪 JavaScript 错误

在这篇文章中,我们将讨论两种不同的追踪 JavaScript 错误的技术。关于 JavaScript 日志控制台和 Remote Inspector 中断点调试的教程将逐步揭示。

操作方法...

最原始和简单的调试方法是在控制台中写入消息。可以使用 JavaScript 对象 console 的以下方法:

  • console.log

  • console.info

  • console.warn

  • console.error

  • console.debug

使用上述任何方法记录的消息将显示在 Tizen IDE 的 JavaScript 日志控制台中。它在启动 Tizen web 应用程序时自动启动。

通过在控制台中记录日志的方式来调试代码并非在所有情况下都有效。在许多情况下,使用断点调试代码更为有用。

按照以下说明启动 Remote Inspector 并通过在源代码中设置断点来追踪 JavaScript 错误:

  1. 启动运行在 Tizen 模拟器和设备上的 Tizen web 应用程序的 Remote Inspector。关于如何执行此步骤的详细说明,请参考前文中的教程。

  2. 点击主工具栏中的 Sources 按钮:操作方法...

    Remote Inspector 中的 Sources 按钮

  3. 点击主工具栏左上角按钮显示导航器。

  4. 选择并打开 JavaScript 文件。

  5. 点击行号设置断点。可以定义多个断点。

  6. 使用控制按钮导航应用程序的断点和源代码:操作方法...

    按钮用于管理和移动 Remote Inspector 中的断点

例如,请看下面这张截图,它是在 Tizen 模拟器中调试 Hello World 应用程序时拍摄的。在 main.js 文件中设置了三个断点,用于追踪硬件返回按钮的行为,如下图所示:

操作方法...

使用 Tizen 模拟器和 Remote Inspector 追踪 JavaScript 错误

工作原理

远程调试器集成在 Tizen IDE 中。如您所见,它提供了强大的工具来调试在 Tizen 模拟器和设备上运行的 Tizen Web 应用程序。使用此工具,您不仅可以调试 JavaScript,还可以检查 HTML 文件的资源、样式和 DOM 结构。

远程调试器基于 WebKit Web Inspector,但它包含了用于远程调试的附加功能。当启动远程调试器时,Chrome 浏览器的一个单独窗口会自动打开。Tizen 模拟器和远程调试器之间通过 HTTP 进行通信,以调试 Tizen Web 应用程序。

另见

获取更多信息,请访问以下链接并查看以下页面:

使用 QUnit 进行单元测试

单元测试是一种通过测试软件的各个单元来自动验证软件的方式。单元测试是测试驱动开发概念的支柱,根据该概念,必须在编写应用程序源代码之前编写测试。

很多用于单元测试的 JavaScript 框架都可以在开源许可下使用,但在本教程中,我们将重点介绍 QUnit。它是一个 jQuery 单元测试框架,非常适用于使用 Tizen Web UI Framework 或 jQuery Mobile 构建的 Tizen Web 应用程序。QUnit 的另一个优点是其许可,因为它在 MIT 许可下发布。

本教程揭示了将 QUnit 集成到 Tizen Web 应用程序中的必要步骤,并创建了几个基本测试。

准备就绪

访问并获取 QUnit 的最新版本。在编写本书时,最新版本是 1.14.0 版。

如何操作...

按照这些说明,从头开始创建一个新的 Tizen Web 应用程序,并将 QUnit 集成到其中。之后,基于本教程中获得的知识,您将能够在任何其他 Tizen Web 应用程序中进行单元测试。

  1. 启动 Tizen IDE 并创建一个新的 Tizen Web 应用程序。

  2. 项目资源管理器中找到应用程序并右键单击它。从弹出的上下文菜单中,导航到新建 | 文件夹

  3. 输入tests作为新文件夹的名称,然后单击完成

  4. 将下载的 QUnit 文件复制到新文件夹中。

  5. 再次在项目资源管理器视图中右键单击项目名称,这次导航到新建 | 文件

  6. 将文件tests.js保存在tests文件夹中。

  7. 打开tests.js并插入几个测试用例:

    QUnit.test( "Tizen Test 1", function( assert ) {
      assert.ok( 1 == "1", "1 is 1" );
    });
    
    QUnit.test( "Tizen Test 2", function( assert ) {
      assert.equal( 0, 0, "0 is 0" );
      assert.notEqual( 2, 1, "2 is not 1" );
    });
    
  8. 按照相同的步骤,创建另一个名为 tests.html 的文件,并将其放在项目的根目录中。

  9. 打开 tests.html 文件并插入以下代码:

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
        <title>QUnit Tests</title>
    

    以下代码行必须包含在前端的源代码中,以确保测试结果能够适应 Tizen 模拟器或设备屏幕的大小。

      <meta name="viewport" content="width=device-width,user-scalable=no"/>
      <link rel="stylesheet" href="tests/qunit-1.14.0.css">
    </head>
    <body>
      <div id="qunit"></div>
      <div id="qunit-fixture"></div>
      <script src="img/qunit-1.14.0.js"></script>
      <script src="img/tests.js"></script>
    </body>
    </html>
    
  10. 编辑 config.xml 文件,并通过更改 content 标签的值,将 tests.html 设置为主页:

    <content src="img/tests.html"/>
    
  11. 在模拟器或设备中启动应用程序,以查看测试结果。

工作原理

测试结果会直接显示在设备或模拟器的屏幕上,当应用程序启动时即会显示。这是由于教程第十步中的 HTML 更改所导致的。

我们在 tests.js 中仅创建了两个基本的测试用例。第一个测试用例验证了 1"1" 在 JavaScript 中值是否相等。第二个测试用例展示了 equal() 断言方法的使用。这两个单元测试都会成功通过;因此,屏幕上将显示类似于以下截图的报告:

工作原理

Tizen 模拟器上显示的 QUnit 报告,表示测试成功完成

让我们对第一个测试用例进行一些小的修改,展示包含失败测试的 QUnit 报告。通过将 == 替换为 === 来修改测试,这样它的代码将变成:

QUnit.test( "Tizen Test 1", function( assert ) {
  assert.ok( 1 === "1", "1 is 1" );
});

这个小修改完全改变了比较关系。在 JavaScript 中,比较运算符 === 不仅检查值,还检查类型。这次测试将失败,因为左侧的操作数是数字,而右侧是字符串。看看下面的截图,了解失败的测试用例是如何报告的:

工作原理

Tizen 模拟器上显示的 QUnit 报告,表示测试失败

在本食谱中,仅使用了两种断言方法。所有断言方法的完整列表可以在以下地址查看:api.qunitjs.com/category/assert/

与本书一起,你可以找到一个示例 Tizen Web 应用程序,其中集成了使用 QUnit 的单元测试。它是按照本食谱中提供的教程创建的。将其导入 Tizen IDE 并运行,以查看你模拟器或设备屏幕上的测试结果。

参见

  • 通过本食谱中的示例,你已经初步了解了 QUnit;接下来,你可以继续通过其 API 文档中的资源进行深入探索,地址:api.qunitjs.com/

  • 此外,QUnit 食谱是一本很好的入门文章。它可以在线访问:qunitjs.com/cookbook/

  • 请记住,市面上还有很多其他优秀的 JavaScript 单元测试工具。Facebook 最近在 GitHub 上发布了他们的产品源代码——一个名为 Jest 的工具,它可以让单元测试变得轻松无痛,访问地址:facebook.github.io/jest/

第十二章。将 Tizen 移植到硬件设备

在本章中,我们将讨论:

  • 设置平台开发环境

  • 在 Ubuntu 或 Debian 中安装开发工具

  • 在 openSUSE 中安装开发工具

  • 在 Fedora 和 CentOS 中安装开发工具

  • 构建 Tizen 平台镜像

  • 将 Tizen 镜像刷入移动设备

  • 启用 3D 加速和 OpenGL

  • 在 Intel NUC 上启动 Tizen

  • 在 Allwinner 设备上启动 Tizen

  • 破解平板电脑并在其上启动 Tizen

介绍

恭喜!你已经到达本书的最后一章!到目前为止,我们已经涵盖了 Tizen 应用开发,并专注于 Web 应用程序。希望你玩得开心。现在是时候迈向下一个层次——Tizen 平台开发。

本章只是 Tizen 平台开发为个人开发者和公司提供的巨大可能性的简要预览。我希望你的 Tizen 之旅不会在本章的最后一个配方中结束,而是继续在平台上进行实验。

这绝对是本书中最先进和最复杂的一章。它提供了构建基于 Tizen 的嵌入式控制系统的指南。包括如何构建 Tizen 平台镜像并将其启动在 ARM 和 x86 设备上的简要教程。这些信息对开发或移植新嵌入式控制系统(如 IVI 或智能家居)到 Tizen 软件平台非常有用。根据本章中的所有配方,你应该能够开始开发自己基于 Tizen 的可穿戴设备和物联网。

设置平台开发环境

Tizen 项目使用在线代码审查系统 Gerrit 和版本控制系统 Git。本配方介绍如何获得访问并配置这两个系统。

准备工作

如果你还没有 www.tizen.org/ 的用户帐户,请在 www.tizen.org/user/register 上填写注册表单。此配方还需要一个互联网连接和一台 Linux 计算机。Tizen 是一个基于 Linux 的平台,平台开发工具与流行的 Linux 发行版兼容。

确保已经安装了 Git。如果系统中没有安装,可以使用以下命令来安装:

  • 在 Ubuntu 或 Debian 上,使用以下命令:

    sudo apt-get update
    sudo apt-get install git
    
    
  • 在 Fedora 或 CentOS 上,使用以下命令:

    yum install git-core
    
    
  • 在 OpenSUSE 上,使用以下命令:

    zypper install git
    
    

如何做到……

按照以下说明配置 SSH 以访问 Gerrit:

  1. 通过在终端运行以下命令并按照屏幕上的指示生成 RSA 密钥:

    ssh-keygen
    
    
  2. 使用你喜欢的文本编辑器,例如 vim,在 ~/.ssh/config 中创建一个 SSH 配置文件,并将以下设置放入其中:

    Host tizen review.tizen.org
    Hostname review.tizen.org
    IdentityFile ~/.ssh/id_rsa
    User <username>
    Port 29418
    

    注意

    别忘了将 <username> 替换为你的 Gerrit 帐户名。

  3. 将上一步生成的文件的全部内容复制到剪贴板。默认情况下,文件存储在 ~/.ssh/id_rsa.pub

  4. 打开网页浏览器,登录到 review.tizen.org/gerrit/

  5. 单击网页右上角的用户名,然后选择设置

  6. 设置页面的菜单中单击SSH 公钥,如下所示:如何操作...

    Gerrit 设置

  7. ~/.ssh/id_rsa.pub 的内容从剪贴板粘贴到标有添加 SSH 公钥的输入框中,并单击添加按钮,如下所示:如何操作...

  8. 通过在终端中运行以下命令验证您已成功配置 SSH 以访问 Gerrit:

    ssh tizen
    
    
  9. 成功访问后,您应该看到以下欢迎消息:

    **** Welcome to Gerrit Code Review ****
    
    

然后,继续本教程的下一部分,并通过以下步骤配置 Git 以访问 Gerrit:

  1. 请将以下命令中显示的 First_NameLast_Name 替换,并执行它以配置 Git 用户名:

    git config --global user.name <First_Name Last_Name>
    
    
  2. <Email> 替换为您在 tizen.org 注册时使用的电子邮件,并运行以下命令以设置 Git 的电子邮件:

    git config --global user.email "<Email>"
    
    

工作原理

Tizen 项目的源代码使用分布式版本控制系统 Git 托管。这是一个由 Linux Torvalds 在 2005 年创建的开源解决方案,最初作为 Linux 内核开发工具。它迅速流行,并在大多数开源项目中得到广泛应用。GitHub 和 Gitorious 提供的服务在 Git 的普及中发挥了重要作用。

本教程的最后两步专门讲解了 Git 的全局选项。git config 命令有两个参数。第一个参数是要更新的设置,第二个参数是新值。

本教程中配置的另一个系统是 Gerrit。这是另一个开源工具,是一个与 Git 紧密集成的基于 Web 的代码审查系统。Gerrit 对于大型项目非常方便,因为它能更集中地使用 Git。其他一些知名的大型开源项目,如 Qt、Android、CyanogenMod、Eclipse、LibreOffice 和 MediaWiki,也依赖于 Git 和 Gerrit。

另请参阅

在 Ubuntu 或 Debian 中安装开发工具

Tizen 平台开发工具适用于几种 Linux 发行版。它们的安装方法因每个发行版而异,但都使用它们的标准安装机制。本教程为在 Ubuntu 和 Debian 上使用 apt-get 提供了逐步安装指南。

如何操作...

如果您使用的是 Ubuntu 或 Debian,请按照以下说明操作:

  1. 使用适当权限的文本编辑器打开文件/etc/apt/sources.list,例如:

    sudo vim /etc/apt/sources.list
    
    
  2. 添加与您正在使用的 Ubuntu 或 Debian 版本对应的 Tizen 开发工具仓库。例如,Ubuntu 14.04 的仓库为:

    deb http://download.tizen.org/tools/latest-release/Ubuntu_14.04/ /
    
    

    注意

    请注意行末的斜杠,指定仓库时不要忘记写上它。可以在download.tizen.org/tools/latest-release/查看适用于不同 Linux 发行版的可用仓库完整列表。

  3. 执行以下命令更新软件包的索引,并与前一步添加的仓库同步:

    sudo apt-get update
    
    
  4. 使用以下命令安装必需的开发工具,GBS 和 MIC:

    sudo apt-get install gbs mic
    
    

工作原理

Debian 被认为是一个稳定的发行版,拥有庞大的支持软件包数据库。Ubuntu 是基于 Debian 构建的,最近已成为第三大使用平台(在操作系统方面,仅次于 Mac OS X 和 Microsoft Windows)。

强大的命令行工具apt-get用于 Debian 和 Ubuntu 的软件包管理。可以用它来安装、升级或删除软件包。本食谱中的整个过程是标准的,因为它遵循了在 Ubuntu 和 Debian 上安装软件包的常见工作流。第一和第二步是 Tizen 特有的,因为必须设置相应开发工具仓库的 URL。

还有更多...

强烈建议保持 Tizen 开发工具的版本最新。在 Ubuntu 和 Debian 中,可以通过执行带有以下参数的apt-get命令来获取所有软件包的最新版本:

sudo apt-get update
sudo apt-get upgrade

或者,可以使用以下命令将单个软件包或软件包列表升级到最新版本:

sudo apt-get install <package>Replace <package> with the name of the package or the list of packages separated by space if you want to upgrade more than one package. For example, if you have already installed GBS run sudo apt-get install gbs to get its version up to date.

另见

在 openSUSE 中安装开发工具

OpenSUSE 是一个免费的、基于 Linux 的通用操作系统。这个发行版的开发由一个同名的社区项目推动,该项目由 SUSE 赞助。这个食谱的目的是帮助 openSUSE 用户安装 Tizen 开发工具。

如何操作...

按照以下步骤在 openSUSE 上安装 GBS 和 MIC:

  1. 添加与您的 openSUSE 版本匹配的 Tizen 开发工具仓库。例如,以下命令会添加与 openSUSE 13.1 兼容的仓库:

    sudo zypper addrepo http://download.tizen.org/tools/latest-release/openSUSE_13.1/ tools
    
    

    注意

    如果你使用的是不同版本的 openSUSE,请在 download.tizen.org/tools/latest-release/ 浏览并找到适合该版本的 Tizen 开发工具仓库。

  2. 按如下方式下载刚刚添加的仓库的元数据:

    sudo zypper refresh
    
    
  3. 使用以下命令下载并安装 GBS 和 MIC:

    sudo zypper install gbs mic
    
    

它是如何工作的

在 openSUSE 上的安装过程与 Ubuntu 和 Debian 上的类似,但命令不同。在 openSUSE 中,包管理的命令行工具是 Zypper。安装的算法仍然与之前的食谱相同,但需要更少的手动操作。第一步是添加仓库,第二步是更新新仓库的元数据,最后一步是安装 GBS、MIC 或其他任何工具。

还有更多...

如果你计算机上的 Tizen 开发工具已经过时,并且想要获取最新版本,请运行以下命令:

sudo zypper refresh
sudo zypper update <package>

<package> 替换为你想要升级的软件包名称。例如,gbsmic

另请参见

在 Fedora 和 CentOS 上安装开发工具

你已经在前面的食谱中看到如何在 Ubuntu、Debian 和 openSUSE 上安装 Tizen 开发工具。现在是时候讨论 Fedora 和 CentOS 了。这些 Linux 发行版的安装过程是相同的,因为 Fedora 和 CentOS 都基于 Red Hat 企业版 Linux (RHEL)。这两个发行版都使用 RPM 包,且由命令行工具 YUM(Yellowdog Updater, Modified)管理。

Fedora 由 Red Hat 拥有,但该项目由社区支持,许多志愿者参与了源代码的开发和维护。Fedora 每六个月发布一个新版本。

与 Fedora 不同,CentOS 的治理结构独立于 Red Hat,尽管该公司赞助了它。CentOS 的第一个版本于 2004 年 5 月发布。

如何操作...

请按照以下教程中的步骤,通过 YUM 在 Fedora 或 CentOS 上安装 Tizen 开发工具:

  1. 通过 wget 将 Tizen 开发工具的仓库下载到 /etc/yum.repos.d,添加该仓库。以 Fedora 20 为例:

    sudo wget -O /etc/yum.repos.d/tools.repo http://download.tizen.org/tools/latest-release/Fedora_20/tools.repo
    
    

    注意

    如果你使用的是 CentOS 或其他版本的 Fedora,请在以下网址浏览并获取与你的操作系统匹配的仓库文件:download.tizen.org/tools/latest-release/

  2. 执行以下命令以更新仓库的元数据:

    sudo yum makecache
    
    
  3. 按照以下步骤安装 GBS 和 MIC:

    sudo yum install gbs mic
    
    

工作原理

如果您已经阅读了前两个食谱,那么您已经熟悉了安装的算法。不同的工具有不同的具体程序,Fedora 和 CentOS 有各自特定的程序。

就像在 Ubuntu、Debian 和 openSUSE 中一样,第一步仍然是添加 Tizen 开发工具的仓库。之后,必须下载新仓库的元数据。最后,使用yum下载来自该仓库的包。

还有更多内容…

为了保持 Tizen 开发工具的最新版本并进行升级,请运行以下命令:

sudo yum makecache
sudo yum update <Package>

<Package>替换为需要升级的软件包的确切名称,例如gbsmic

另见

构建 Tizen 平台镜像

本食谱展示了制作 Tizen 平台镜像所需的配料和步骤。提供了逐步教程以及许多外部链接。根据这些信息,您将能够构建 Tizen 平台镜像,并在兼容设备上启动它们,接下来,您需要按照以下食谱中的说明进行操作。

准备工作

您即将开始一个耗时的过程。确保您有一台强力计算机来构建 Tizen 平台镜像,否则请准备好等待较长时间。尽管在配置较低的系统上也可以构建 Tizen 平台镜像,但根据我的个人经验,推荐的系统配置是全新 Intel Core i7 处理器和 8GB RAM。

应该设置平台开发环境,并按照前面食谱中的说明正确安装平台开发工具。

如何操作…

按照这些指南从头开始构建 Tizen 平台镜像:

  1. 创建一个目录~/bin/,并将其包含在PATH中,如下所示:

    mkdir ~/bin/
    PATH=~/bin:$PATH
    
    
  2. 下载 repo 脚本,并通过运行以下命令为其添加执行权限:

    cd ~/bin/
    wget http://commondatastorage.googleapis.com/git-repo-downloads/repo
    sudo chmod a+x ~/bin/repo
    
    
  3. 创建一个新目录,Tizen 源代码将下载到该目录,操作如下:

    mkdir ~/tizen
    cd ~/tizen
    
    

    注意

    上述示例中的目录名称是tizen。请根据需要设置一个适合您的目录名称。

  4. <user>替换为您的 Gerrit 用户名,然后执行以下两个命令通过 SSH 下载 Tizen Common 的源代码:

    repo init -u ssh://<user>@review.tizen.org:29418/scm/manifest -b tizen -m common.xml
    repo sync
    
    

    注意

    将清单更改为ivi.xml以下载 IVI 配置文件的源代码,或者更改为mobile.xml以下载移动配置文件的源代码。可用的分支和远程仓库的完整列表可以在source.tizen.org/documentation/developer-guide/getting-started-guide/building-packages-locally-gbs#available-branches-and-the-corresponding-remote-repos找到。

  5. 打开.gbs.conf文件并进行配置。例如,这是 Tizen Common 的默认配置:

    [general]
    tmpdir=/var/tmp/
    profile = profile.tizen3.0_common
    work_dir=.
    
    [repo.tizen3.0_x86]
    url=${work_dir}/pre-built/toolchain-x86/
    
    [repo.tizen3.0_arm]
    url=${work_dir}/pre-built/toolchain-arm/
    
    [profile.tizen3.0_common]
    repos=repo.tizen3.0_x86,repo.tizen3.0_arm
    buildconf=${work_dir}/scm/meta/build-config/build.conf
    

    选择以下选项之一,并去掉行首的#以启用它:

    # For wayland ia32
    # buildconf=${work_dir}/scm/meta/build-config/build-ia32-wayland.conf
    # For emulator32 wayland
    # buildconf=${work_dir}/scm/meta/build-config/build-emulator32-wayland.conf
    # For wayland x86_64
    # buildconf=${work_dir}/scm/meta/build-config/build-x86_64-wayland.conf
    # For wayland arm32
    # buildconf=${work_dir}/scm/meta/build-config/build-arm-wayland.conf
    # For wayland arm64
    # buildconf=${work_dir}/scm/meta/build-config/build-arm64-wayland.conf
    

    注意

    IVI 和移动配置文件的默认配置可以在source.tizen.org/documentation/developer-guide/getting-started-guide/building-packages-locally-gbs查看。

  6. 使用 GBS 和与目标 CPU 架构匹配的命令构建所有包,如下所示:

    • 对于 i586,使用以下命令:

      gbs build -A i586 --threads=4 --clean-once
      

      注意

      如果你正在构建 Tizen 2 平台镜像,请在之前的命令中附加--exclude=gcc,cmake,filesystem,aul,libmm-sound,libtool

    • 对于 armv7l,使用以下命令:

      accel_pkgs="bash,bzip2-libs,c-ares,cmake,coreutils,diffutils,eglibc,elfutils-libelf,elfutils-libs,elfutils,fdupes,file,findutils,gawk,gmp,gzip,libacl,libattr,libcap,libcurl,libfile,libgcc,liblua,libstdc++,make,mpc,mpfr,ncurses-libs,nodejs,nspr,nss-softokn-freebl,nss,openssl,patch,popt,rpm-build,rpm-libs,rpm,sed,sqlite,tar,xz-libs,zlib,binutils,gcc"
      gbs build -A armv7l --threads=4 --clean-once --exclude=${accel_pkgs},filesystem,aul,libmm-sound,libtool
      
      
  7. download.tizen.org下载适当的 kickstart 文件。例如,以下命令将下载用于构建 Tizen 2.2.1 的 kickstart 文件,以用于 RD-PQ:

    wget http://download.tizen.org/releases/2.2.1/tizen-2.2.1/builddata/image-configs/RD-PQ-REF.ks
    
    
  8. 编辑 repo 部分,并将--baseurl参数的值更改为指向本地构建。此时,值必须以file://为前缀,并跟随绝对路径。

  9. 最后,运行以下命令来使用 kickstart 文件创建 Tizen 镜像:

    gbs createimage –ks-file=RD-PQ-REF.ks
    
    

    注意

    如果系统有超过 4GB 的 RAM,可以将--tmpfs作为额外的参数附加。

工作原理

Tizen 是一个开源软件平台,任何人都可以免费下载其源代码并从头开始构建。这个过程虽然费时,但并不难。

主要使用的工具是Git 构建系统GBS)和MeeGo 镜像创建器MIC)。GBS 是一个命令行工具,用于构建 Tizen 包。MIC 是继承自 MeeGo 的工具,用于创建镜像。现在,它的功能已经嵌入到 GBS 中,镜像可以通过运行gbs createimage命令直接创建。或者,你仍然可以通过create参数直接调用 MIC。

这个流程的步骤非常直观。首先,你需要获取源代码,然后构建包,最后使用 MIC 和适当的 kickstart 文件准备一个 Tizen 镜像。

Tizen 镜像可以为 ARMv7 和 i586 兼容的处理器构建。根据目标设备,你需要使用适当的配置,如第六步所示。

另见

将 Tizen 镜像刷入移动设备

第一个 Tizen 参考设备是 RD-210,于 2012 年在 Tizen 开发者大会上宣布。如今已经过时,并且不再发布适用于其的新版本 Tizen 移动配置文件。其后继者在一年后以 RD-PQ 代号发布,截至本文撰写时,仍兼容所有最新的 Tizen 发布版本。RD-PQ 基于三星 Galaxy S3,具有类似的硬件规格。

本文提供了关于刷写这两款 Tizen 参考设备的指导方针。请注意,刷机过程虽然简单,但潜在风险较高。在执行任何设备操作之前,请仔细阅读所有说明以及提供链接中的信息。

准备工作

刷机过程非常精细。请做好准备,因为即使是小小的错误也可能导致永久性的不良结果,甚至最糟糕的情况下可能会砖化设备。

确保您拥有一台兼容 Tizen 的设备,并且其电池已充电。此外,您需要一根 USB 数据线,用于将设备连接到计算机。

需要使用 Linux 发行版的个人计算机。刷机过程依赖于一个称为 lthor 的工具。确保您可以成功设置 Tizen 开发工具存储库,并运行以下命令安装 lthor

sudo apt-get update
sudo apt-get install lthor

作为预防措施,强烈建议您使用备用电源供应的计算机,例如充电电池充足的笔记本电脑,在刷机过程中最大程度地减少电力中断的风险。

如何做…

以下教程描述了 Tizen 参考设备(如 RD-PQ 和 RD-210)的刷机过程:

  1. 为你的设备构建适当的 Tizen 映像,或者从 download.tizen.org/releases/ 下载。

  2. 关闭设备。

  3. 同时按下音量减和电源硬件按钮,将设备引导至下载模式。

  4. 通过 USB 电缆将设备连接到计算机。

  5. 通过替换以下命令中的 <Tizen image> 为下载文件的名称,并执行该命令,来将映像刷入设备:

    sudo ./lthor <Tizen image>
    
    

    注意

    如果你打算将 RD-210 从 Tizen 1.0 Larkspur 更新到更高版本,则需要进行额外操作。更多信息请参考以下链接:source.tizen.org/documentation/reference/flash-device#RD-PQ_RD-210

还有更多内容...

在 Ubuntu 上,刷机过程的最后一步可能会因以下任何错误而失败:

  • 握手失败错误:

    USB port is detected: /dev/ttyACM0
    
    line 328: failed to read signature bytes
    line 603: handshake failed
    line 922: failed to open port (null)
    
    
  • 端口打开错误:

    USB port is detected : /dev/ttyACM0
    
    port open error!!
    : Device or resource busy
    line 954: failed to open port (null)
    
    

这两个问题已经在 Tizen 邮件列表中多次讨论过。它们是由 modemmanager 引起的,modemmanager 尝试通过 USB 端口与附加设备通信,从而阻止了 lthor 的正常工作。

如果你遇到上述任何错误,请使用以下命令卸载 modemmanager,然后重新运行 lthor

sudo apt-get purge modemmanager

另外,如果你希望保留 modemmanager,请执行以下操作:

  1. 移除或将 modemmanager 的 D-BUS 服务配置文件移到其他位置,具体操作如下:

    sudo mv /usr/share/dbus-1/system-services/org.freedesktop.ModemManager.service ~/org.freedesktop.ModemManager.service
    
    
  2. 通过以下命令终止当前正在运行的所有 modemmanager 实例:

    sudo stop modemmanager
    sudo killall modem-manager
    
    

欲获取更多关于 lthor 的故障排除技巧,请访问 wiki.tizen.org/wiki/Troubleshooting_lthor_on_Ubuntu

另请参见

启用 3D 加速和 OpenGL

本教程将指导你如何在为 Tizen 设备刷机后,立即启用 3D 加速和 OpenGL,适用于搭载 Mali GPU 的设备。

准备就绪

如果你已经刷入 Tizen 参考设备,例如 RD-PQ,在按照前述步骤操作后,你会在平台启动后立即注意到一个警告,如下所示:

准备就绪

在 RD-PQ 上首次启动 Tizen 2 时,合成器警告

由于缺少 3D 加速和 OpenGL 的驱动程序,系统会显示警告。该问题影响许多内置应用程序,并干扰它们的正常运行。必须安装适用于 Mali DDK 的第三方驱动程序以解决该问题。

安装过程相当简单。它需要一台安装了 Tizen SDB 的计算机、一个互联网连接,当然,还需要 Tizen 设备。

如何操作...

安装 Mali DDK 有多种方式。无论选择哪种方式,最终结果都是相同的。启用硬件加速的以下方法非常简单:

  1. 下载与已刷入设备上的 Tizen 版本兼容的 Mali DDK。以下是适用于 Tizen 2 的 Mali DDK 版本:

    注意

    Mali DDK 的源代码并不开放。请访问 source.tizen.org/ 查找最新版本的二进制文件。

  2. 在计算机上提取下载的文件,例如:

    tar -xvzf hw_accel.tar.gz
    
    
  3. 将 Tizen 设备连接到计算机,并使用 SDB 将提取的文件复制到设备中。以下示例中的命令将文件复制到 /home/ 目录:

    sdb -d root on
    sdb -d push libdrm-exynos-gem-*.rpm /home/
    sdb -d push libump-*.rpm /home/
    sdb -d push opengl-es-mali400mp-*.rpm /home/
    
    
  4. 登录设备,并进入你已复制文件的目录,例如/home/,如下所示:

    sdb -d shell
    cd /home/
    
    
  5. 按如下方式删除旧软件包:

    rpm -e --nodeps opengl-es-virtual-drv
    
    
  6. 按如下方式安装新软件包以启用硬件加速:

    rpm -ivh --force *.rpm
    
    
  7. 最后,通过执行以下命令刷新文件系统缓存,并重启 Tizen 设备:

    sync
    reboot
    
    

或者,你可以通过首先将下载的 tarball 复制到设备上并直接提取它,来减少该过程的手动操作。

工作原理

Tizen 参考设备 RD-PQ 配备 Mali 400-MP4 GPU。其驱动程序作为 RPM 文件的 tarball 提供,因为 Tizen 作为平台使用 RMP 包管理器。需要使用 SDB 将文件复制到设备上,然后安装软件包。更改只有在设备重启后才会生效。

另见

在 Intel NUC 上启动 Tizen

Tizen 是一个支持 ARM 和 x86 架构的软件平台。英特尔作为 Tizen 项目的主要贡献者之一,正在为支持英特尔处理器的 x86 架构投入大量精力。这一架构在 40 多年前的 70 年代末首次推出,64 位版本的 x86 于 2003 年发布。

本教程专门介绍如何在搭载英特尔处理器的设备上刷写兼容 x86 架构的 Tizen 镜像。目前市场上有许多兼容设备,但本教程的重点是基于英特尔 Atom 处理器 E3815 型号的 Intel NUC。

准备工作

本教程需要一个用来刷写 Tizen 镜像的工具。它由 bmap-tools 包提供。按照 Tizen 开发工具的安装指南进行安装。例如,在 Ubuntu 上,可以使用以下命令安装:

sudo apt-get install bmap-tools

你还需要一个至少 4 GB 磁盘空间的 USB 存储棒和一台兼容的计算机,如 Intel NUC。Tizen 镜像将被刷入 USB 存储棒,其他所有数据将被完全擦除。为了防止数据丢失,请确保在继续操作之前已备份 USB 存储棒中的数据。

如何执行...

执行描述的操作以创建带有 Tizen 系统的可启动 USB 存储棒:

  1. 将 USB 存储棒插入计算机。

  2. 使用 fdisk -l 或查看 dmesg 的日志来识别设备。

  3. 卸载设备。在基于 Unix 的系统上,可以按如下方式进行。将 X 替换为 USB 存储设备的 ID:

    umount /dev/sdX*
    
    
  4. 使用 bmaptool 下载 Tizen 镜像,并将其复制到 USB 驱动器。如果不确定下载哪个镜像,建议下载里程碑版本,如下所示:

    bmaptool <Tizen> /dev/sdX
    
    

<Tizen> 替换为你本地磁盘上的镜像或镜像的 URL。

一旦你有了带有 Tizen 的可启动 USB 存储棒,你可以继续在具有 Intel 处理器的兼容设备上启动它:

  1. 将 USB 存储棒插入 Intel NUC。

  2. 打开设备。

  3. 通过按 F2 进入 BIOS。

  4. 修改启动顺序,并将 USB 存储棒设置为最高优先级。

  5. 保存更改并继续。如果一切正常,Tizen 会很快启动。

工作原理

Tizen 被划分为多个配置文件。Tizen IVI 和 Common 更适合 Intel 架构。在本教程中,我们使用了 Tizen Common 的里程碑版本。这种版本应当稳定,建议如果不确定选择哪个版本时,可以依赖这个版本。

更多内容...

按照前述过程,你已经创建了一个带有 Tizen 系统的可启动 USB 存储棒,你可以将其复制到设备的持久存储中。

以下教程描述了将 Tizen 复制到 Intel NUC 内置存储的其中一种方法。需要第二个 USB 存储棒。

  1. 将第二个 USB 存储棒插入计算机,并将相同的 Tizen 镜像作为原始文件复制到其中。之后,拔掉这个 USB 存储棒。

  2. 当 Tizen 从第一个 USB 存储棒运行时,将第二个 USB 存储棒插入 Intel NUC。

  3. 启动 Tizen 终端并以 root 用户登录。

  4. 使用 fdisk –l 检测第二个 USB 存储棒和内部 eMMC 存储。

  5. 使用 umount 卸载内部 eMMC 存储。

  6. 将第二个 USB 存储棒中的 Tizen 镜像复制到 eMMC。使用以下命令,替换 <Tizen image> 为第二个 USB 存储棒中的文件,替换 <storage> 为 eMMC,例如 /dev/mmcblk0

    bzcat <Tizen image> | dd of=<storage> bs=512k oflag=sync conv=sparse
    
    
  7. 关闭设备,拔掉所有 USB 存储棒,然后重新启动设备。

  8. 请确保设备从内部存储启动,如果一切正常,Tizen 将很快启动。

作为替代方案,您可以选择不使用第二个 USB 存储设备,而是在 Intel NUC 上启动 Tizen 并启用网络连接。之后,您可以将 Tizen 镜像复制到运行操作系统的 USB 存储设备中。

另见

在 Allwinner 设备上启动 Tizen

Allwinner 是一家中国公司,其核心业务与 SoC 的开发相关。该公司成立于 2007 年,并于 2010 年凭借其搭载 Cortex-A8 处理器的 SoC(即 A10)在全球广受欢迎。2013 年,Allwinner 发布了 A20,搭载双核 Cortex-A7 ARM 处理器。

2013 年 4 月,Allwinner 因其在全球 Android 平板 AP 出货量中的领先地位获得 ARM 奖。许多受欢迎的单板计算机,如 OLinuXino、Cubieboard 和 Banana Pi 也使用 Allwinner 处理器,具有 ARMv7 兼容架构。所有搭载 Allwinner 处理器的设备也被称为 Sunxi。

由于其低价格,搭载 Android 的 Sunxi 设备在市场上具有极好的渗透率。它们对于 Tizen 生态系统也非常重要,因为它们为大量 Sunxi 设备的拥有者打开了大门。此外,搭载 Allwinner 处理器的开源硬件设备,如 OLinuXino 系列板卡,为初创公司和预算有限的爱好者提供了出色的创新机会。

本教程提供了将 Tizen 移植到 Sunxi 设备的完整指南。请注意,市面上有成千上万款搭载 Allwinner SoC 的设备。每款设备的规格不同,因此您需要根据您的设备以及所使用的 Tizen 版本调整教程。

准备工作

为本书中的最先进教程做准备。所提供的说明适用于通用的 Sunxi 设备,请根据您目标设备厂商的具体规格进行调整。

本教程按原样提供,不提供任何形式的保证。操作风险自负。请仔细阅读所有说明,并遵循硬件厂商的建议和指导。请注意,任何错误可能会导致设备损坏或其他不良行为。

为了顺利完成此教程,您需要一台 Linux 计算机、一台带有 microSD 卡槽的 Sunxi 设备,并且必须具备以下条件:

  • Tizen 平台开发环境设置

  • 安装了 Tizen 平台开发工具

  • 适用于 ARMv7 兼容设备的 Tizen 镜像

如果未能遵守上述任何要求,请参考前面的教程。

如何操作...

以下教程内容包括构建 Linux-sunxi 内核、U-Boot 加载程序、将 Tizen 刷入 microSD 卡以及在 Sunxi 设备上启动:

  1. 通过运行以下命令设置工具链来构建内核和引导加载器:

    sudo apt-get update
    sudo apt-get install gcc-4.7-arm-linux-gnueabihf ncurses-dev uboot-mkimage build-essential git
    
    

    注意

    Debian 用户可能需要将 www.emdebian.org/debian 的仓库添加到 /etc/apt/sources.list 中。

  2. 创建一个目录,并使用 Git 下载 U-Boot 引导加载器的源代码到该目录:

    mkdir sunxi/
    cd sunxi/
    git clone -b sunxi https://github.com/linux-sunxi/u-boot-sunxi.git
    
    

    注意

    强烈建议你使用设备供应商验证过的源代码版本。

  3. 进入通过 git clone 创建的目录:

    cd u-boot-sunxi/
    
    
  4. 使用 GNU make 工具从头开始构建 U-Boot 引导加载器。例如,以下命令将使用 makefile 为开源硬件开发板 A20-OLinuXino-MICRO 构建 U-Boot:

    make a20-olinuxino_micro CROSS_COMPILE=arm-linux-gnueabihf-
    
    
  5. 检查文件 spl/sunxi-spl.bin u-boot.bin u-boot-sunxi-with-spl.bin 是否存在,以验证 U-Boot 引导加载器的构建是否成功。

  6. 返回到主目录,并准备通过下载其源代码来构建 Linux-sunxi 内核。

    cd ..
    git clone https://github.com/linux-sunxi/linux-sunxi
    
    
  7. 进入目录 linux-sunxi,并使用以下命令,结合适当的 <defconfig> 为目标平台构建内核:

    cd linux-sunxi/
    make ARCH=arm <defconfig>
    
    

    注意

    项目中包含的所有 defconfig 文件位于目录 linux-sunxi/arch/arm/configs/。建议将任何第三方 defconfig 文件放置在相同的目录中。某些供应商(例如 Olimex)提供他们自己的 defconfig 文件。

  8. 可选地,你可以使用以下命令构建内核模块:

    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 INSTALL_MOD_PATH=out modules
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 INSTALL_MOD_PATH=out modules_install
    
    
  9. 将 microSD 卡插入计算机并识别它。请注意,microSD 卡上的所有信息将被完全清除,Tizen 系统将被覆盖。

  10. <X> 替换为 microSD 卡的 ID,并启动 fdisk

    sudo fdisk /dev/sd<X>
    
    
  11. 通过在 fdisk 中运行 p 命令来获取 microSD 卡的总大小。这是一个 4 GB microSD 卡的示例输出:

    Command (m for help): p 
    
    Disk /dev/sdc: 4026 MB, 4026531840 bytes
    
    
  12. 通过将上一步获取的大小除以单个柱面的大小来计算柱面数量,单个柱面的大小等于头数乘以扇区数再乘以单个扇区的大小。

    注意

    单个柱面的大小为 255 个头、63 个扇区、每个扇区 512 字节,总大小为 8225280 字节。所以,如果例如 microSD 卡的总大小为 4026531840 字节,那么柱面的数量就是 489。

  13. 使用 fdisk 中的 d 命令删除现有分区,如下所示。重复此操作,直到删除所有分区:

    Command (m for help):  d
    Partition number (1-4): 1
    
    
  14. 配置 microSD 卡的头、扇区和柱面,按照如下方式;将 <cylinders> 替换为第 12 步计算出的值:

    Command (m for help): x
    Expert command (m for help): h
    Number of heads (1-256, default 30): 255
    Expert command (m for help): s
    Number of sectors (1-63, default 29): 63
    Warning: setting sector offset for DOS compatibility
    Expert command (m for help): c
    Number of cylinders (1-1048576, default 2286): <cylinders> 
    
    
  15. 创建一个引导分区,其余部分留给 Linux 分区:

    Expert command (m for help): r
    Command (m for help): n
    Command action
    e extended
    p primary partition (1-4)
    p
    Partition number (1-4): 1
    First cylinder (1-123, default 1):
    Using default value 1
    Last cylinder or +size or +sizeM or +sizeK (1-123, default 123): +64M (see note above)
    Command (m for help): n
    Command action
    e extended
    p primary partition (1-4)
    p
    Partition number (1-4): 
    2
    First cylinder (10-123, default 10):
    Using default value 10
    Last cylinder or +size or +sizeM or +sizeK (10-123, default 123):
    Using default value 123
    
    
  16. 为引导分区设置 FAT32 文件系统:

    Command (m for help): t
    Partition number (1-4): 1
    Hex code (type L to list codes): c
    Changed system type of partition 1 to c (W95 FAT32 (LBA))
    * You have to format 1st partitions with vfat32 filesystem.
    Command (m for help): a
    Partition number (1-4): 1
    
    
  17. 通过再次运行 p 命令验证分区是否正确。

  18. 使用 w 命令保存所有更改:

    Command (m for help): w
    The partition table has been altered!
    
    Calling ioctl() to re-read partition table.
    
    
  19. <X> 替换为 microSD 卡的标识符,并按如下方式格式化分区:

    sudo mkfs.vfat -F 32 -n boot /dev/sd<X>1
    sudo mkfs.ext4 -L rootfs /dev/sd<X>2
    sudo mkfs.ext4 -L data /dev/sd<X>3
    sudo mkfs.ext4 -L UMS /dev/sd<X>4
    
    
  20. 卸载 microSD 卡并按如下方式写入引导加载器:

    umount /dev/sd
    <X>*
    dd if=u-boot-sunxi/u-boot-sunxi-with-spl.bin of=/dev/sd<X> bs=1024 seek=8
    
    
  21. 完成后,挂载 microSD 卡,并将 Linux-sunxi 内核和配置文件(例如 script.bin)复制到启动分区,这些文件通常由硬件厂商提供。下面是一个示例:

    mkdir /mnt/sd1
    mount /dev/sd<X>1 /mnt/sd1
    cp linux-sunxi/arch/arm/boot/uImage /mnt/sd1
    cp script.bin /mnt/sd1
    sync
    umount /dev/sd<X>1
    
    
  22. 确保以如下方式卸载所有 microSD 卡的分区:

    umount /dev/sd<X>*
    
    
  23. 将每个 Tizen 镜像复制到相应的分区。在以下命令中,将 <image> 替换为 Tizen 镜像,将 <X> 替换为 microSD 卡的标识符,将 <N> 替换为分区号:

    sudo dd if=/dev/<image> of=/dev/sd<X><N> bs=1024 count=1
    
    
  24. 可选地,你可以重新挂载启动(FAT32)分区,并创建 uEnv.txt,这允许热插拔某些配置项,如显示输出。将 disp.screen0_output_type 改为 1 以启用 LCD 显示,3 以启用 HDMI,4 以启用 VGA。下面是一个示例配置,用于在 uEnv.txt 中启用 HDMI 显示:

    console=tty0
    loglevel=5
    extraargs=console=ttyS0,115200 disp.screen0_output_type=3 disp.screen0_output_mode=EDID:800x480p33 hdmi.audio=EDID:0
    
    
  25. 卸载并拔下 microSD 卡,然后将其插入 Sunxi 设备,启动设备以启动 Tizen。

它是如何工作的

这个教程包含了三个主要的组成部分:引导加载程序、内核和 Tizen 镜像。

U-Boot 是一个适用于 ARM、PowerPC、MIPS 和其他处理器的嵌入式设备通用引导加载程序。它被广泛应用于 Sunxi 设备,针对这些设备的一个分支托管在 GitHub 上。在教程的第二步中,U-Boot 的源代码从 GitHub 克隆,并在后续步骤中进行构建。

Linux-sunxi 是 Linux 内核的一个分支,托管在 GitHub 上。它专门为带有 Allwinner SoC 的设备进行了适配。其构建过程在步骤 6 到步骤 8 的说明中有详细介绍。

该教程的最后一个也是最复杂的部分是设置可引导的 microSD 卡。这部分从第 9 步开始。第一个分区采用 FAT32 文件系统,这意味着它可以很容易地在不同操作系统的计算机上挂载和编辑。这非常方便,因为你可能需要在 Microsoft Windows 计算机上更改一个二进制文件或编辑 uEnv.txt

本教程包含了许多 Linux 命令。如果你不确定它们的工作原理,或者仅仅想查看它们的详细信息,请查阅相应的 Linux 手册页。例如,键入 man dd 以了解该命令的更多信息。

另请参见

破解平板并在其上启动 Tizen

Allwinner 处理器可以在市场上找到许多设备中。根据其产品目录,Allwinner 在 2013 年为 Android 平板出货了最多的 ARM 处理器。

前面的步骤已经证明 Tizen 可以在配有 Allwinner 处理器的开发板上运行,接下来的步骤是如何在现有的 Android 平板上启动 Tizen。本步骤提供了如何通过逆向工程提取平板的二进制配置文件的指南。

准备工作

请确保满足以下前提条件:

  • 一台 Android 平板(或最终智能手机),需要有 microSD 卡插槽,并且配备 Allwinner ARMv7 兼容处理器,如 A20、A13、A10、A10 等。

  • 一台安装了Android 调试桥ADB)的计算机,带有 Android SDK。

  • 按照前面的步骤准备好 Tizen 镜像的可启动 microSD 卡。

如何操作...

按照这些指南提取平板的二进制配置文件,将其放入 Tizen 镜像中,并通过 microSD 卡从平板启动 Tizen。请注意,提供的说明是按原样给出的。过程复杂,操作需自行承担风险。

  1. 打开平板,等待其 Android 系统启动图像加载完成,然后在设置 | 开发者选项中启用USB 调试

  2. 将平板连接到计算机并进入开发者模式。

  3. 执行以下命令以进入平板的远程 Shell:

    adb shell
    
    
  4. 挂载并访问平板的 NAND 内存,方法如下:

    mkdir /sdcard/nanda
    mount -t vfat /dev/block/nanda /sdcard/nanda
    
    
  5. 退出 Shell,并使用adbscript.bin复制到计算机,方法如下:

    adb pull /sdcard/nanda/script.bin .
    
    
  6. 将 microSD 卡插入计算机。

  7. 在 microSD 卡的 FAT32 分区上覆盖script.bin,并删除uEnv.txt(如果存在的话)。

  8. 从计算机中弹出 microSD 卡。

  9. 关闭平板。

  10. 将 microSD 卡插入平板。

  11. 再次开启平板。如果一切按预期工作,Tizen 将直接从 microSD 卡启动。

它是如何工作的

这个命令行工具 Android 调试桥(ADB)用于连接 Allwinner 的 Android 平板,并复制其二进制配置文件。它是一个客户端-服务器程序,其目的与 SDB 完全相同,但适用于 Android 设备。

Sunxi 平板的内部存储,也就是它们的 NAND 闪存,作为可以挂载的设备,正如步骤 4 所示。之后,可以直接访问文件,并将其传输到计算机。这一技巧使得配置文件的逆向工程变得简单,并简化了其他平台(如 Tizen)和 Linux 发行版(如 Debian)的启动过程。

ADB 命令pull用于将script.bin从 Android 平板下载到计算机。pull命令的第一个参数是文件在设备上的位置,第二个参数是计算机中必须保存该文件的目的地。

还有更多…

要读取其配置文件,必须将从 Android 复制过来的二进制文件转换为fex文件。开源项目 Linux-sunxi,托管在 GitHub 上,提供了一个简单的命令行工具来完成这项工作。执行以下简单操作将script.bin转换为fex文件:

  1. 使用git下载 sunxi-tools 的源代码,方法如下:

    git clone https://github.com/linux-sunxi/sunxi-tools.git
    
    
  2. 从源代码构建bin2fex,方法如下:

    make bin2fex
    
    
  3. 运行bin2fexscript.bin转换为script.fex,例如:

    ./bin2fex script.bin > script.fex
    
    

另见

posted @ 2025-07-05 19:50  绝不原创的飞龙  阅读(35)  评论(0)    收藏  举报