在这篇文章中,我们将介绍如何使用Ubuntu系统提供的online account API来实现我们的微博。通过这篇文章,开发者可以使用同样的方法来实现对其它Web Service的访问,比如淘宝,优酷等网站的访问。我们实现的新浪微博的Scope的截图如下。本篇文章的重点是介绍online account API的使用,所以我不会像以前的那些教程一样从最基本的Scope开发介绍。更多关于online account的介绍在网址找到。
1)创建一个最基本的weibo Scope
我们通过使用Ubuntu SDK来创建一个最基本的Scope。在这里我们使用如下的Scope template:
按照如上的步骤,我们可以创建一个我们自己的一个最基本的weibo Scope,虽然里面显示的还是天气。
2)为online account添加必要的文件
我们同时也把在根目录下的“manifest.json.in”及“weibo.apparmor”移到“click”目录下,当然,我们也需要对根目录下的“CMakeLists.txt”做必要的修改。修改后的CMakeLists.txt文件如下:
project(weibo CXX)
cmake_minimum_required(VERSION 2.8.10)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" "${CMAKE_MODULE_PATH}")
# We require g++ 4.9, to avoid ABI breakage with earlier version.
set(cxx_version_required 4.9)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
if (NOT CMAKE_CXX_COMPILER_VERSION MATCHES "^${cxx_version_required}")
message(FATAL_ERROR "g++ version must be ${cxx_version_required}!")
endif()
endif()
# Set strict and naggy C++ compiler flags, and enable C++11
add_definitions(
-fno-permissive
-std=c++11
-pedantic
-Wall
-Wextra
-fPIC
-DQT_NO_KEYWORDS
)
include(GNUInstallDirs)
find_package(PkgConfig)
find_package(Intltool)
# We depend on Boost for string trimming
find_package(
Boost
REQUIRED
)
# Search for our dependencies
pkg_check_modules(
SCOPE
libunity-scopes>=0.6.0
net-cpp>=1.1.0
REQUIRED
)
find_package(Qt5Core REQUIRED)
include_directories(${Qt5Core_INCLUDE_DIRS})
# Add our dependencies to the include paths
include_directories(
"${CMAKE_SOURCE_DIR}/include"
${Boost_INCLUDE_DIRS}
${SCOPE_INCLUDE_DIRS}
)
# Do not remove this line, its required for the correct functionality of the Ubuntu-SDK
set(UBUNTU_MANIFEST_PATH "click/manifest.json.in" CACHE INTERNAL "Tells QtCreator location and name of the manifest file")
set(UBUNTU_PROJECT_TYPE "Scope" CACHE INTERNAL "Tells QtCreator this is a Scope project")
# Important project paths
set(CMAKE_INSTALL_PREFIX /)
set(SCOPE_INSTALL_DIR "/weibo")
set(GETTEXT_PACKAGE "weibo")
set(PACKAGE_NAME "weibo.ubuntu")
set(SCOPE_NAME "${PACKAGE_NAME}_weibo")
set(SCOPE_INSTALL_NAME "${PACKAGE_NAME}_weibo")
set(SCOPE_ACCOUNTS_NAME "${PACKAGE_NAME}_accounts")
set(SYMBOL_MAP "${CMAKE_SOURCE_DIR}/data/${PACKAGE_NAME}.map")
add_definitions(-DGETTEXT_PACKAGE="${GETTEXT_PACKAGE}")
add_definitions(-DSCOPE_NAME="${SCOPE_NAME}")
add_definitions(-DSCOPE_INSTALL_NAME="${SCOPE_INSTALL_NAME}")
add_definitions(-DSCOPE_ACCOUNTS_NAME="${SCOPE_ACCOUNTS_NAME}")
add_definitions(-DPACKAGE_NAME="${PACKAGE_NAME}")
# If we need to refer to the scope's name or package in code, these definitions will help
#This command figures out the target architecture and puts it into the manifest file
execute_process(
COMMAND dpkg-architecture -qDEB_HOST_ARCH
OUTPUT_VARIABLE CLICK_ARCH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
#configure_file(manifest.json.in ${CMAKE_CURRENT_BINARY_DIR}/manifest.json)
# Install the click manifest
#install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json DESTINATION "/")
#install(FILES "weibo.apparmor" DESTINATION "/")
# Make these files show up in QtCreator
file(GLOB_RECURSE
_PO_FILES
"po/*.po"
)
add_custom_target(hidden_files
ALL
SOURCES
# manifest.json.in
# weibo.apparmor
data/${SCOPE_NAME}.ini.in
po/POTFILES.in
po/${GETTEXT_PACKAGE}.pot
${_PO_FILES}
)
add_subdirectory(click)
# Add our main directories
add_subdirectory(src)
add_subdirectory(data)
add_subdirectory(po)
# Set up the tests
enable_testing()
add_subdirectory(tests)
add_custom_target(
check
${CMAKE_CTEST_COMMAND} --force-new-ctest-process --output-on-failure
)
这里主要的修改是影藏显示“manifest.json.in”及“weibo.apparmor”文件的显示,应为这两个文件已经移到“click”目录中了。同时也注释掉如下的语句,应为这项工作在“click”目录中的“CMakeLists.txt”中已经做了。
#configure_file(manifest.json.in ${CMAKE_CURRENT_BINARY_DIR}/manifest.json)
# Install the click manifest
#install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json DESTINATION "/")
#install(FILES "weibo.apparmor" DESTINATION "/")
另外,我们为了能够正确地显示项目,我们也对如下的句子做了修改:
set(UBUNTU_MANIFEST_PATH "click/manifest.json.in" CACHE INTERNAL "Tells QtCreator location and name of the manifest file")
这里我们加上了“click”路径。同时我们也加入了如下的定义:
set(SCOPE_INSTALL_NAME "${PACKAGE_NAME}_weibo")
set(SCOPE_ACCOUNTS_NAME "${PACKAGE_NAME}_accounts")
set(SYMBOL_MAP "${CMAKE_SOURCE_DIR}/data/${PACKAGE_NAME}.map")
add_definitions(-DGETTEXT_PACKAGE="${GETTEXT_PACKAGE}")
add_definitions(-DSCOPE_NAME="${SCOPE_NAME}")
add_definitions(-DSCOPE_INSTALL_NAME="${SCOPE_INSTALL_NAME}")
add_definitions(-DSCOPE_ACCOUNTS_NAME="${SCOPE_ACCOUNTS_NAME}")
add_definitions(-DPACKAGE_NAME="${PACKAGE_NAME}")
这样这些变量及定义可以在项目的其它文件中被正确地引用了。
下面,我们来看看“click”目录下的文件:
apparmor.json
{
"template": "ubuntu-scope-network",
"policy_groups": [
"accounts"
],
"policy_version": 1.2
}
注意这里在“policy_groups”里我们多加入了一个称作为“accounts”的policy。这个是必须的,否则不可以正常工作。
manifest.json.in
这个文件的显示如下:
{
"description": "This is a tutorial for weibo scope",
"framework": "ubuntu-sdk-14.10",
"architecture": "@CLICK_ARCH@",
"hooks": {
"weibo": {
"scope": "weibo",
"apparmor": "apparmor.json",
"account-application": "weibo.application",
"account-service": "weibo.service"
},
"accounts": {
"account-provider": "weibo.provider",
"account-qml-plugin": "qml-plugin"
}
},
"maintainer": "XiaoGuo, Liu <xiaoguo.liu@canonical.com>",
"name": "@PACKAGE_NAME@",
"title": "weibo scope",
"version": "0.1"
}
weibo.application.in
<?xml version="1.0" encoding="UTF-8"?>
<application>
<description>Weibo scope</description>
<desktop-entry>@SCOPE_INSTALL_NAME@.desktop</desktop-entry>
<services>
<service id="@SCOPE_INSTALL_NAME@">
<description>Watch your favorite Weibo messages</description>
</service>
</services>
</application>
这个是微博Scope的描述文件。它定义了Scope的service id及描述
weibo.service.in
<?xml version="1.0" encoding="UTF-8"?>
<service>
<type>sharing</type>
<name>Weibo scope</name>
<icon>weibo/icon.png</icon>
<provider>@SCOPE_ACCOUNTS_NAME@</provider>
<translations>unity-scope-weibo</translations>
</service>
这个service文件描述了微博Scope的service信息。
weibo.provider.in
这是一个微博的account provider信息。这是一个重要的文件。如果我们不能正确地设置这个文件,可能我们不能正确地访问微博account。
<?xml version="1.0" encoding="UTF-8"?>
<provider>
<name>Weibo</name>
<icon>weibo/icon.png</icon>
<translations>unity-scope-weibo</translations>
<plugin>generic-oauth</plugin>
<domains>.*weibo\.com</domains>
<single-account>true</single-account>
<template>
<group name="auth">
<setting name="method">oauth2</setting>
<setting name="mechanism">web_server</setting>
<group name="oauth2">
<group name="web_server">
<setting name="Host">api.weibo.com</setting>
<setting name="AuthPath">oauth2/authorize</setting>
<setting name="TokenPath">oauth2/access_token</setting>
<setting name="RedirectUri">https://api.weibo.com/oauth2/default.html</setting>
<setting name="ResponseType">code</setting>
<setting name="ClientId">your developer key</setting>
<setting type="as" name="AllowedSchemes">['https','http']</setting>
<setting name="ClientSecret">your developer secret</setting>
<setting name="ForceClientAuthViaRequestBody" type="b">true</setting>
</group>
</group>
</group>
</template>
</provider>
我们需要在“ 微博开放平台”去申请开发者key及secret。同时,我们一定要记得在微博的设置中做如下的设置,否则我们不能得到正确的数据。
“click”目录下的CMakeLists.txt文件内容如下:
function(configure_scope_files)
foreach(_file ${ARGV})
configure_file(
"${_file}.in"
"${CMAKE_CURRENT_BINARY_DIR}/${_file}"
@ONLY
)
endforeach()
endfunction()
configure_scope_files(
manifest.json
weibo.provider
weibo.service
weibo.application
)
add_custom_target(hidden_files1
ALL
SOURCES
apparmor.json
)
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/manifest.json"
"apparmor.json"
"${CMAKE_CURRENT_BINARY_DIR}/weibo.provider"
"${CMAKE_CURRENT_BINARY_DIR}/weibo.service"
"${CMAKE_CURRENT_BINARY_DIR}/weibo.application"
DESTINATION ${CMAKE_INSTALL_PREFIX}
)
install(
DIRECTORY
"qml-plugin"
DESTINATION ${CMAKE_INSTALL_PREFIX}
)
这里它对该目录下的文件进行了安装。
为了能够对Scope的设置文件“weibo.ubuntu_weibo.ini.in”进行本地化的支持,我们对“data\CMakeListx.txt”加入如下的句子:
intltool_merge_translations(
"${CMAKE_CURRENT_SOURCE_DIR}/${SCOPE_NAME}.ini.in"
"${CMAKE_CURRENT_BINARY_DIR}/${SCOPE_INSTALL_NAME}.ini"
ALL
UTF8
)
这样它可以提取里面相应的英文,并在“po”目录中的.pot文件中进行翻译。
经过我们这样的修改后,我们的最基本的具有online account的设置文件已经基本已经做好了。我们可以在我们的手机或模拟器中运行我们的Scope了。在运行时,
我们选择“yes”继续运行。我们可以看到如下的画面:
者和我们所创建的最基本的Scope没有任何的差别,我们可以在手机的如下地址查看该目录的内容:
这个是我们所创建weibo provider的地方。
3)对代码进行修改
我们在上面已经对online account的配置文件做了修改。下面我们来对我们的cpp代码进行修改,为了能够使得我们使用online account,我们在query.cpp文件中加入如下的代码:
const static string SEARCH_CATEGORY_LOGIN_NAG = R"(
{
"schema-version": 1,
"template": {
"category-layout": "grid",
"card-size": "large",
"card-background": "color:///#1ab7ea"
},
"components": {
"title": "title",
"background": "background",
"art" : {
"aspect-ratio": 100.0
}
}
}
)";
void Query::run(sc::SearchReplyProxy const& reply) {
add_login_nag(reply);
...
}
void Query::add_login_nag(const sc::SearchReplyProxy &reply) {
// if (getenv("VIMEO_SCOPE_IGNORE_ACCOUNTS")) {
// return;
// }
qDebug() << "SCOPE_INSTALL_NAME: " << SCOPE_INSTALL_NAME;
qDebug() << "SCOPE_ACCOUNTS_NAME: " << SCOPE_ACCOUNTS_NAME;
sc::OnlineAccountClient oa_client(SCOPE_INSTALL_NAME, "sharing", SCOPE_ACCOUNTS_NAME);
// Check if our service is authenticated
bool service_authenticated = false;
int count = oa_client.get_service_statuses().size();
qDebug() << "count: " << count;
for ( sc::OnlineAccountClient::ServiceStatus const& status :
oa_client.get_service_statuses())
{
if (status.service_authenticated)
{
service_authenticated = true;
qDebug() << "Sevice is authenticated!";
qDebug() << "account id: " << status.account_id;
qDebug() << "client id: " << QString::fromStdString(status.client_id);
qDebug() << "service enabled: " << status.service_enabled;
qDebug() << "secret: " << QString::fromStdString(status.client_secret);
qDebug() << "access token: " << QString::fromStdString(status.access_token);
accessToken_ = QString::fromStdString(status.access_token);
// pass the access token to the client so that http request can be made
client_.setAccessToken(accessToken_);
break;
}
}
if (!service_authenticated)
{
qDebug() << "Service is not authenicated!";
sc::CategoryRenderer rdr(SEARCH_CATEGORY_LOGIN_NAG);
auto cat = reply->register_category("weibo_login_nag", "", "", rdr);
sc::CategorisedResult res(cat);
res.set_title(_("Log-in to Weibo"));
oa_client.register_account_login_item(res,
query(),
sc::OnlineAccountClient::InvalidateResults,
sc::OnlineAccountClient::DoNothing);
reply->push(res);
}
}
我们点击“Log-in to Weibo”按钮:
我们使用我们自己的微博的账号进行登陆,在代码中,我们可以看到:
我们打开手机中的“系统设置”,再打开“账号”,当我们完成我们自己的账号登陆微博后,可以看到:
这说明我们的online account设置等已经是成功的。我们更进一步对我们的client代码进行修改,我们可以看到如下的画面:
整个项目的source code可以在如下的地址下载:
在使用代码时,一定要在“click/weibo.provider.in”中填入自己的开发者key及secret。
更多关于online account API的例子: