关闭与 NFC 在 Tizen 上共享的范围数据
PUBLISHED
近场通讯
近场通信 (NFC) 是一个国际标准 ISO/IEC 18092,指定一个接口和协议以方便紧密耦合设备进行简单的无线连接。 NFC 有三组应用程序方案:
- 接近无线标签的设备
- 接近其他设备(对等网络)的设备
- 接近销售终端机的设备
文中所描述的示例应用程序属于第二组应用程序:对等。
有关 NFC 的更多详细信息,请访问以下网址:http://www.nfc-forum.org/。
示例应用程序功能
ShareContacts 示例应用程序演示如何使用 Tizen 平台的 NFC、联系人、邮件和文件系统 Api。
启动后,该应用程序显示存储在默认通讯簿的所有联系人列表,按照“名字”属性排序。 在列表中的每个元素被注册来处理"swiperight"和"swipeleft"事件。 "Swipeleft"事件显示来自所选联系人号码的消息。 您可以从列表中查看一个或多个消息。 "Swiperight"事件将选定的联系人添加到我们想要发送的联系人列表中。 您可以同时发送一个或多个联系人和一个或多个邮件。 单击"发送"按钮后,如果检测到的第二个目标或您测试示例应用程序:
- 使用两个设备:NDEF 消息(稍后介绍)从第一个设备发送到第二个设备。 此外,包含在 NDEF 消息中的需收费记录将保存到第一个设备的文件系统中的"nfc-data"文件(如果文件不存在,则创建,否则覆盖)。 接收到的数据将显示在第二个设备上的应用程序。
- 在模拟器上:包含在 NDEF 消息中的需收费记录存储在模拟器文件系统中的"nfc-data"文件中。 模拟器如何模拟接收 NDEF 消息将在稍后介绍。
此示例应用程序使用 jQuery Mobile 1.2.0 框架,并包含 jQuery 1.8.0 库。
如何使用 Event Injector 在模拟器上测试应用程序?
要通过 NFC 发送任何内容,应检测目标。 在使用模拟器的情况下,您可以使用 Tizen SDK 提供的 Event Injector (Window->Show view -> Event Injector)。
图 2:Event Injector:NFC 视图
要在模拟器上发现新的设备,您也可以单击在对等部分发现的 P2P。 现在,您可以与模拟器往来发送 NDEF 消息。
从模拟器发送 NDEF 消息
Event Injector 不接收由模拟器发送的 NDEF 消息。 所以我们需要创建一个单独的测试路径以启动模拟器上的应用程序。 此路径包括将 NDEF 消息中的有效负载记录写到一个该用户可以读取的文件系统,然后发回该模拟器。 也就是说,在仿真器上启动的应用程序将 NDEF 消息发送给自己。 从模拟器发送 NDEF 消息方式如下图所示:
图 3:发送 NDEF 消息图解
要查看保存在“nfc-data”文件中的数据,您应该使用连接资源管理器视图。
连接资源管理器视图显示连接到 SDK 的设备和模拟器。 它为连接的设备和模拟器提供以下操作:
|
您可以通过示例应用程序在模拟器上浏览文件系统并找到保存的文件(位置:mnt > ums > Documents > nfc-data)。
您可以在连接的设备(在本例中为模拟器)和主机系统之间传输文件。 要执行此操作,请将所选的文件拖到所需的主机系统路径。
图 4:正在从已连接的设备中拖动一个文件
该文件仅包含最后一个发送的 NDEF 消息记录的有效载荷。 文件结构如下所示:
Identifier of the NDEF Record: Content of the NDEF Record
您可以使用"NDEF 记录的内容"作为从 Event Injector 发送到模拟器的 NDEF 新消息的有效载荷。
发送 NDEF 消息到模拟器
要将一条 NDEF 消息发送到模拟器,您需要有关 NDEF 消息有效负载的内容。 为此,您应该首先从模拟器发送一条 NDEF 消息(如前一章中所介绍)或使用这一条:
BEGIN%3AVCARD%0D%0AVERSION%3A3.0%0D%0AN%3AJ.%3BMaria%3B%3B%3B%0D%0AFN%3AMaria%20J.%0D%0AORG%3A%0D%0ATEL%3BVOICE%3BVOICE%3BPREF%3A123456789%0D%0AEND%3AVCARD%0D%0A
要发送一条 NDEF 消息到模拟器:
图 5:NDEF 消息部分
在 NDEF 消息部分:
- 选择的记录类型名称格式:NDEF_TNF_WELL_KNOWN;
- 输入记录类型名称:‘T’;
- 请输入有效载荷(前面所述);
- 点击“添加”按钮。
NDEF 消息的结构将在稍后描述(创建和发送 NDEF 消息)。
注:请记住将记录类型名称更改为 ‘T’(默认为 'U')。 ‘T’ 代表文本数据。
如有需要,您可以为 NDEF 消息添加多个 NDEF 记录(最多:5)。
要发送一条 NDEF 消息到模拟器,请在 Peer to Peer 部分单击 P2P Send [5](如果此选项未启用,则单击P2P Discovered)。
如果一切正常,在模拟器上启动的示例应用程序应显示收到的 NDEF 消息的数据。
注:发送到模拟器的 NDEF 消息可以包含联系人或 sms 消息。 您不能在一条 NDEF 消息中混合包含 sms 的 NDEF 记录和包含联系人的 NDEF 记录。 这不受示例应用程序支持。
如何使用两个设备测试应用程序?
图 6:使用两个设备发送 NDEF 消息图示
要使用两个设备测试示例应用程序:
- 在这两个设备上启动示例应用程序,并将它们互相接近移动后应检测到目标。
- 添加联系人或要发送的邮件,然后单击"发送"按钮。
- 收到的 NDEF 消息的数据应由第二个设备上启动的示例应用程序显示。
应用程序配置
若要使用在文中提到的 Tizen API 功能,您必须在 config.xml 文件中声明必要的功能。 为此:
- 打开 config.xml 文件。
- 选择功能选项卡。
- 检查或添加功能:
- http://tizen.org/api/tizen,
- http://tizen.org/api/application.read,
- http://tizen.org/api/contact,
- http://tizen.org/api/filesystem,
- http://tizen.org/api/messaging.read,
- http://tizen.org/api/messaging.write,
- http://tizen.org/api/nfc.admin,
- http://tizen.org/api/nfc.p2p。
您可以在文档中找到有关特权和 API 的更多详细信息 (Tizen Web App Programming > Programming Guide > Device)。
NFC API
NFC 设备供电
在使用 NFC 之前,您应该在设备上获取默认的 NFC 适配器和将它设置为通电状态。
var nfcAdapter; //contains callback functions: onattach, ondetach and onreceive var callbacks; function onPowerOn() { detectTarget(); } function onPowerOnFails(e) { console.error('Power On error: ' + e.name + " : "+ e.message); } try { nfcAdapter = tizen.nfc.getDefaultAdapter(); callbacks = callback; nfcAdapter.setPowered(true, onPowerOn, onPowerOnFails); } catch (e) { nfcAdapter = null; }
要在设备上获取默认的 NFC 适配器,可以使用 tizen.nfc.getDefaultAdapter() 方法。 然后您可以控制本地 NFC 行为:打开/关闭 NFC 适配器或调查目标。 要为适配器充电,您必须使用 setPowered() 函数。 此方法需要以下参数:NFC 适配器的状态、您想要的设置 (boolean)、成功 (onPowerOn) 和错误 (onPowerOnFails) 回调函数。 回调是可选的。
检测其他设备
DetectTarget() 方法调用 setPeerListener() 方法来注册检测到 NFC 对等目标(onSuccess) 时要调用的回调函数。 出现故障时,则调用 (err) 错误回调函数。
try { nfcAdapter.setPeerListener(onSuccess, err); } catch (e) { console.error(e.name + " : " + e.message); }
OnSuccess() 方法指定 onattach 回调函数(当设备可用时调用)和 ondetach 回调函数(不可用时)。
var nfcTarget; var onSuccess = { onattach : function sucAttach(target) { nfcTarget = target; nfcTarget.setReceiveNDEFListener(onreceive, err); callbacks.onattach(); }, ondetach : function() { nfcTarget = null; callbacks.ondetach(); nfcTarget.unsetReceiveNDEFListener(); } };
连接目标调用 onattach 函数,该函数:
- 接收一个代表目标设备的 NFCPeer 对象;NFCPeer 对象分配给全局变量 nfcTarget,
- 调用 setReceiveNDEFListener() 方法。
SetReceiveNDEFListener() 方法注册当接收来自连接的 NFC 对等目标的 NDEF 消息时要调用的回调函数。 此方法采用两个参数:成功接收消息时调用的成功 (onreceive) 和错误 (err) 回调。
Callbacks.onreceive() 方法如下所示:
onreceive: function(message) { if (message.records[0].text.substring(0, 3) === "sms") messageManager.handleMessageReceive(message); else contactsManager.handleContactReceive(message); }
上述函数将在稍后介绍。
当设备变得不可用时将调用 ondetach() 函数。 它将一个 null 值分配给全局变量 nfcTarget,并且调用 unsetReceiveNDEFListener() 方法,用于注销接收来自连接的 NFC 对等目标的 NDEF 消息侦听器。 您可以在应用程序生命期内设置和取消设置侦听器任意次数。
创建和发送 NDEF 消息
使用 NFC 标准开发人员可以传输任何类型的文本或二进制数据。 通常发送的数据格式被称为 NFC 数据交换格式 (NDEF)。 NDEF 定义 NFC 设备和标记之间共同的数据格式。 更多详细信息,请参阅有关 NDEF 的 Web 页。
图 7:示例应用程序中的 NDEF 消息结构
在我们的示例应用程序中,NDEF 消息由记录组成,每个记录包含 sms 邮件或联系人。
图 8:通过 NFC 发送联系人 & 图 9:通过 NFC 发送邮件
示例应用程序使用 NFC 适配器。 单击"发送"按钮后,示例应用程序检查第二个设备是否连接。 如果连接,则 NDEF 消息已发送。 否则,将显示相关的弹出消息。
要发送 NDEF 消息,示例应用程序将使用 sendTextNDEF() 函数。 它采用两个参数:
- 包含联系人/消息主体的 recordsToSend 数组转换为字符串
- 处理发送操作的成功 (callback.success) 或失败 (callback.error) 的对象类型。
方法的代码如下所示:
var textRecords = []; try { for (i in recordsToSend) { textRecords.push( new tizen.NDEFRecordText(encodeURIComponent(recordsToSend[i]), 'en-US', 'UTF16')); } var ndefMessage = new tizen.NDEFMessage(textRecords); nfcTarget.sendNDEF(ndefMessage, callback.success, callback.error); } catch (e) { console.error("Error: " + e.message); }
EncodeURIComponent() 方法对 recordsToSend 数组中的特殊字符进行编码。 已编码的字符串作为第一个参数用于创建一个 NDEF 记录对象。 第二和第三个参数是:语言代码的字符串值 ('en-US') 和编码的类型 (' UTF16')。 创建的 NDEFRecordText 对象放入 textRecords 数组。 示例应用程序使用此数组来创建 NDEF 消息。 创建消息后,它发送到使用 nfcTarget.sendNDEF() 方法的 NFC 对等目标设备。 此方法采用三个参数:NDEF 消息发送 (ndefMessage) 和两个回调函数,它们处理成功 (callback.success) 或失败 (callback.error) 的情况。
注:文本记录是 NFC 论坛众所周知的类型并被标记为"T"(在 NFC 二进制编码中:0x54)。
RecordsToSend 数组可以包含转换为字符串的联系人或消息,消息可转换为 JSON 并在开始处添加 ‘sms’ 以将它们与联系人区分。
正在接收 NDEF 消息
图 10:显示收到消息的页面 & 图 11:显示收到联系人的页面
如前文所述,收到调用 onreceive() 方法的消息时:
onreceive: function(message) { if (message.records[0].text.substring(0, 3) === "sms") messageManager.handleMessageReceive(message); else contactsManager.handleContactReceive(message); }
该函数识别接收的消息类型(sms 消息或联系人),并调用适当的处理程序。
HandleMessageReceive() 方法读取每个 NDEF 消息记录,对其进行解码,并将其作为对象添加到记录的数组,如下所示:
var records = []; // Read received data to 'records' array for (var i = 0; i < message.records.length; i++) { try { records[i] = jQuery.parseJSON(decodeURIComponent(message.records[i].text.slice(3))); } catch (e) { shareContacts.onError(e); } }
jQuery parseJSON() 方法采用一个参数和 JSON 字符串,并返回 Javascript 对象。
该方法负责设置下一个显示页面,创建已接收(或搜索)消息的项。 每个项包括接收日期和消息开头最多 14 个字符。 注册列表元素来处理"swipeleft"事件。 "Swipeleft"事件将打开一个显示消息页面,在这里您可以看到完整的消息正文。
如果收到的 NDEF 消息中包含联系人数据,则调用 handleContactReceive() 函数。 此方法从收到的数据创建联系人,并将它们放入 receivedContacts 全局数组。 它也打开新的页面并显示收到的联系人,且每个联系人下面显示"添加到通讯簿"选项。 您可以添加接收的联系人,不做任何修改或根据您的需要修改。 稍后将介绍如何创建和添加联系人到通讯簿中。
消息 API
通过消息 API 可以使用多种功能,如检索可用的消息服务、发送 SMS 消息、搜索消息并管理它们等。 要使用消息 API 的任何功能,您必须在 config.xml 文件(前面介绍)中声明必要功能。
您可以在这里找到有关消息 API 的详细信息。
查找消息
消息对象允许存储信息(如收件人、发件人、主题、正文、类型等),并允许应用程序通过 MessageStorage 方法检索消息的内容。
在示例应用程序中,我们搜索从选定的电话号码(短语)收到的消息。 为此,您应该创建筛选器:
var fromFilter = new tizen.AttributeFilter("from", "EXACTLY", phrase);
创建的筛选器将被传递到服务对象的 findMessages() 方法。 要获取的服务对象,请执行以下操作:
tizen.messaging.getMessageServices('messaging.sms', onGetServices, shareContacts.onError);
getMessageServices() 为给定帐户检索给定类型的消息传递服务。 该方法采用四个参数:要检索的服务类型(在此示例应用程序中,SMS 的服务对象已获得,所以我们使用"messaging.sms"类型)、成功和错误回调和 serviceId(在示例应用程序中省略)。 第三和第四个参数是可选的。
查找消息服务已成功完成,成功回调函数将返回在设备上可用的 MessageService 对象(服务)的数组。 我们假设只有返回一个服务。
function onGetServices( services ) { try { services[0].messageStorage.findMessages(fromFilter, callback.success, callback.error); } catch (e) { console.error("Searching failed: " + e.name + ":" + e.message); } }
我们使用服务对象来调用带以下参数的 findMessages() 方法:fromFilter(前面已介绍),以及成功和错误回调。 Callback.success 函数调用 messageManager.display() 方法(前面已介绍)。
在 ‘Drafts’ 文件夹中保存邮件
图 9 是一个显示接收到消息的页面。 每个列表中的项可以在选择并单击“保存”按钮后保存于 ‘Drafts’ 文件夹中。
for (var i = 0; i < checkedMessages.length; i++) { // Create message var message = new tizen.Message("messaging.sms", { plainBody : displayedMesssages[checkedMessages[i]].body }); // Save message in Drafts messages.addToDraft(message,{ success : function() { console.log("Messages added to Draft Messages Folder"); }, error : function(e) { console.error("Cannot add message to draft folder: " + e.message); } }); }
checkedMessages 是一个包含所选消息 ID 的数组。 displayedMessages 是一个数组,包含(在这种情况下)接收消息的对象。 单击“保存”按钮后,示例应用程序使用所选消息(从显示消息)正文来创建一个新的消息对象,用作addToDraft() 方法的第一个参数。 AddToDraft() 方法如下所示:
addToDraft : function(message, callback) { function onGetServices(services) { try { services[0].messageStorage.addDraftMessage(message, callback.success, callback.error); } catch (e) { console.error("Searching failed: " + e.name + ":" + e.message); } } tizen.messaging.getMessageServices('messaging.sms', onGetServices, shareContacts.onError); }
前一章已经介绍了 getMessageServices() 方法。
如果成功找到消息服务,则成功回调函数将返回可用 MessageService 对象(服务)的数组到设备。 我们使用服务对象来调用带以下参数的 addDraftMessage() 方法:消息(前面所述)、成功和错误回调。 此方法将草稿消息添加到 MessageStorage。 NFC 收到的消息可在 Drafts 文件夹中找到。
联系人 API
Tizen.contact 对象包含电话号码、电子邮件地址等信息。 联系人 API 提供了读取、创建、删除和更新特定地址簿中的联系人的功能。 要使用任何联系人功能,您必须在 config.xml 文件(前文已介绍)中声明必要功能。
关于 Contact API 的详细信息,请参阅:文档和地址簿管理 (Documentation and the Address Book Management) 文章。
将联系人信息转换为 VCARD
要取得联系人信息,您需要获取 AddressBook 对象的实例。 您可以使用下面的方法获取默认的通讯簿:
var addressbook = tizen.contact.getDefaultAddressBook();
一旦您检索了默认的通讯簿,您可以获得一个联系人实例。
for (var i = 0; i < contactsToSend.length; i++) { contactData = addressbook.get(contactsToSend[i]); }
ContactsToSend 数组中包含您选择进行发送的联系人 Id。
您现在可以将联系人项序列化为 vCard 3.0 格式的字符串类型。
try { var textNDEF = contactData.convertToString("VCARD_30"); console.log('textual representation of the contact is: ' + textNDEF); } catch (err) { console.error('The following error occurred while converting: ' + err.name); return; }
vCard 3.0 格式是 Tizen 平台支持的唯一格式。 它包含我们想要导出的联系人信息。 交换联系人的格式定义了 RFC 2426 vCard MIME 目录配置文件。
创建和添加联系人
如果收到的 NDEF 消息中包含联系人数据,则创建一个新的联系人,该联系人稍后可以添加到通讯簿。
可以创建联系人对象:
- 使用 vCard 3.0 格式的字符串表示形式(先前转换为字符串的联系人),如下所示:
var tmp = new tizen.Contact(contactData, "VCARD_30");
- 通过设置联系人对象的属性,如下所示:
var contact = new tizen.Contact({ name : new tizen.ContactName({ firstName : tmp.name.firstName, lastName : tmp.name.lastName }), phoneNumbers : [ new tizen.ContactPhoneNumber(tmp.phoneNumbers[0].number) ] });
我们使用两个以上办法。
示例应用程序使您可以将创建的联系人添加到手机地址簿。 点击“添加到通讯簿”按钮调用函数,该函数检查手机地址簿中是否存在该电话号码(我们想要添加的联系人)。 如果存在,则显示相关的弹出窗口,您可以决定您是否想要重复这一号码。 否则,该联系人以以下方式添加:
add : function(contact) { try { addressbook.add(contact); } catch (e) { console.error("Unable to add contact to address book"); return false; } return true; },
前一章介绍了如何获取 AddressBook 对象(地址簿)的实例。 Add () 方法只有一个参数:要添加的联系人。
Filesystem API
Tizen Filesystem API 提供了对设备的文件系统的访问。 要使用 Filesystem 对象的任何功能,您必须在 config.xml 文件(前面已介绍)中声明必要功能。
有关 Filesystem API 的详细信息,请访问:文档 (Documentation)。
示例应用程序使用 FileSystem API 来解析目录路径、创建文件和/或写入到文件。 有关这些操作的信息可参阅"在 Tizen 自定义 2D 图形 (Custom 2D Graphics on Tizen)"文章(使用Filesystem Tizen 设备 API (Using the Filesystem Tizen Device API) 章节)。
总结
从本文中,您学习了:
- 如何使用 NFC API 来检测连接的设备,创建 NDEF 记录,创建/发送/接收 NDEF 消息,
- 如何在 Tizen 模拟器上测试 NFC 功能,
- 如何使用 Event Injector,
- 如何在模拟器上使用连接资源管理器视图查看文件系统,
- 如何查找所选联系人的消息,
- 如何将消息保存到 ‘Drafts’ 文件夹中,
- 如何将联系人转换为 VCARD 3.0,
- 如何创建联系人,
- 如何将联系人添加到默认的通讯簿。
我们希望本文可以帮助您利用 NFC 功能创建 Tizen web 应用程序。 使用 NFC 非常容易在紧密耦合的两个设备之间发送数据如:Url、地理坐标等。