上一篇文章中我使用了几个基本的例子来解释了AllJoyn框架中各个模块的功能。本文我将从代码层面解释如何从零开始搭建一个AllJoyn核心应用
本文中所有的代码都可以从Git中自行下载:代码链接
AllJoyn应用的整体框架
本文所使用的应用可以被切分成三个模块, 从而更好地帮助我们理解AllJoyn框架:
主程序应用代码 - Main主要功能:
- 处理命令行输入并输出
- 在代码中创建并放置调用函数, 管理AllJoyn中API的互相通讯
AllJoyn API代码 - MyAllJoynCode主要功能:
- 表示如何启动AllJoyn框架
- 为服务层的广播与发现服务使用About Feature属性
- 为应用绑定一个Session并追踪主机的SessionId值
- 使用Session的Id来跟踪使用者
- 通过MyFirstBusObject与其他AllJoyn实体进行互相沟通
总线对象的实现 - MyFirstBusObject主要功能:
- 创建并实现一个AllJoyn接口
- 表示如何发送一个总线方法并获得反馈
- 表示如何发送一个信号以及无会话的信号
- 表示如何获取信号
如上所示代码不能单独运行,必须与其他两个模块共同启动才能确保应用的正常。 上面的分类只是用于更好的理解使用AllJoyn的API使用方式,从而为开发者提供便利。
模块分析
每个AllJoyn应用都应该创建一个总线附属(BusAttachment), 启动后连接到AllJoyn的路由上(AllJoyn Router)。 总线附属对象可以让应用调用AllJoyn的API, 创建方式如下所示:
mBusAttachment = new BusAttachment("MyFirstApplica
tion", true);
/* Start the msg bus */
if (ER_OK == status) {
status = mBusAttachment->Start();
} else {
printf("BusAttachment::Start failedn");
}
/* Connect to the daemon */
if (ER_OK == status) {
status = mBusAttachment->Connect();
if (ER_OK != status) {
printf("BusAttachment Connect failed.n");
}
}
创建好了总线附属后,下一步需要确定应用的基本功能。 这一章所介绍的应用不但是客户端,同时也是服务器端,也就是说,应用是一个P2P结点。 因此为了实现连接功能,我们需要加入BindSession。
/* 将会话绑定到端口,从而接收所有的加入请求 */
SessionOpts opts(SessionOpts::TRAFFIC_MESSAGES, true, SessionOpts::PROXIMITY_ANY, TRANSPORT_ANY);
SessionPort sp = SESSION_PORT_ANY;
status = mBusAttachment->BindSessionPort(sp, opts, *this);
if (ER_OK != status) {
printf("无法绑定会话端口n");
}
由于应用中使用的端口可以为任何端口,因此我们使用SESSION_PORT_ANY。 我们希望AllJoyn框架能够为应用分配端口并传递到About数据中。 与此同时, 为了能够通知其他应用我们的存在, 我们需要设置About特性
/* 设置About数据, 使应用能够广而告知 */
mAboutData = new AboutPropertyStoreImpl();
// 设置一个独一无人的ID, 比如说设备的Mac地址
// 为应用设置一个随机值, 这种方法在商业应用中也很常见
mAboutData->setDeviceId(getDeviceId());
mAboutData->setDeviceName("MyDeviceName");
// AllJoyn应用的全局辨识符 - recommend to use an online GUID generator to create
// use a random value for this application, this should persist in a comercial application
mAboutData->setAppId(getAppId());
std::vector
languages(1);
languages[0] = "en";
mAboutData->setSupportedLangs(languages);
mAboutData->setDefaultLang("en");
mAboutData->setAppName(appName);
mAboutData->setModelNumber("Tutorial5000");
mAboutData->setDateOfManufacture("8/15/2014");
mAboutData->setSoftwareVersion("1.0 build 1");
mAboutData->setAjSoftwareVersion(ajn::GetVersion());
mAboutData->setHardwareVersion("N/A");
mAboutData->setDescription("This is the my first AllJoyn Application!", "en");
mAboutData->setManufacturer("Company", "Me");
mAboutData->setSupportUrl("http://www.allseenalliance.org");
/* Initialize the About feature Service side */
AboutServiceApi::Init(*mBusAttachment, *mAboutData);
/* Register the port with About feature that was set when BindSession called */
status = AboutServiceApi::getInstance()->Register(sp);
/* Register the About feature with AllJoyn */
status = mBusAttachment->RegisterBusObject(*AboutServiceApi::getInstance());
接下来,应用就可以开始集合了。我们已经为其他应用的寻找与互联编写好了平台
/*设置并注册开发者的总线应用*/
/**
* Here is where we add the objects we wish to expose.
* A developer would modify this section to add different BusObjects.
*/
mMyFirstBusObject = new MyFirstBusObject(*mBusAttachment);
/* Now register the object with AllJoyn and About */
QStatus status;
status = mBusAttachment->RegisterBusObject(*mMyFirstBusObject);
if (ER_OK != status) {
printf("Could not register the BusObject with the BusAttachmentn");
}
std::vector interfaces;
for( int i = 0; i < mMyFirstBusObject->getNumberOfInterfaces(); i++) {
interfaces.push_back(mMyFirstBusObject->getInterfaceName(i));
}
status = AboutServiceApi::getInstance()->AddObjectDescription(mMyFirstBusObject->GetPath(), interfaces);
if (ER_OK != status) {
printf("Error returned by AddObjectDescription (%s).n", QCC_StatusText(status));
}
BusObject与MyFirstBusObject包含了我们互相进行通讯的所有信息,并且将我们事先的所有的API集进行了开放,允许其他应用进行调用
BusAttachment在创建、启动并连接后, 连接的设置就弄好了, 设备的细节也自动设置好, 而且对象也被注册好了。 下一章我们就可以制作注册调用,从而让应用能够找到我们的first_app应用。