如何将 Microsoft 服务添加到你的应用 (HTML)
[ 本文适用于编写 Windows 运行时应用的 Windows 8.x 和 Windows Phone 8.x 开发人员。如果你要针对 Windows 10 进行开发,请参阅 最新文档 ]
你可以在这里了解如何将 Microsoft 服务中的功能添加到你的 Windows 运行时应用,以使其能访问用户的个人资料信息、用户的 Microsoft OneDrive 中的文件和照片以及 Outlook.com 信息。 本教程中的步骤始于一个空白应用,然后添加相应功能以登录到用户的 Microsoft 帐户并获取用户的个人资料信息,以将其显示在应用中。
要点 本主题中的教程演示了 Windows 应用商店应用。还可以将 Microsoft 服务添加到 Windows Phone 应用商店应用。虽然 Windows Phone 用户界面不支持浮出控件,但是,你必须在 Windows Phone 应用商店应用中使用页面,以实现在本主题中使用的浮出控件的功能。
你需要了解的内容
技术
先决条件
- Windows 8
- Microsoft Visual Studio
- Live SDK
- 一个 Windows 应用商店开发人员帐户
- 要在应用中使用的两个图像文件(PNG 格式)
说明
步骤 1: 创建“空白应用程序”项目并包括 Live SDK
通过以下步骤从 Visual Studio 模板创建你的新应用:
- 从 Visual Studio 的“文件”菜单中,单击“新建项目...”****。
- 在“新建项目...”对话框中,转至“已安装”>“模板”>“JavaScript”>“Windows 应用商店”。
- 选择“空白应用程序”****。
- 输入你的新应用的名称和位置,然后单击“确定”。
- 构建并测试你的应用。它在启动时应该显示一个仅显示“此处显示内容”"****的空白页面。如果你看到此信息,关闭应用并继续。
步骤 2: 将应用添加到你的 Windows 应用商店开发人员帐户
要让你的应用使用 Live SDK 访问的云服务,必须在 Windows 应用商店开发人员帐户中注册该应用。你不需要将应用提交到 Windows 应用商店进行认证。只需在 Windows 应用商店开发人员帐户中输入它的名称。
步骤 3: 添加应用数据和“设置”浮出控件
使用 Live SDK 的 Windows 应用商店应用必须至少执行以下两个操作:
- 允许用户登录到其 Microsoft 帐户和注销(如果可以)。
- 显示隐私策略,该策略描述了你将如何保护你的应用访问的个人数据。
有关登录和注销体验及隐私策略的详细信息,请参阅 Microsoft 帐户登录的要求。
在 Windows 应用商店应用中,通过“设置”浮出控件来访问这些体验。
要向你的应用中添加弹出窗口,请执行以下操作:
创建“帐户”弹出窗口页面。
为“帐户”弹出窗口文件创建新文件夹。在“解决方案资源管理器”中,右键单击项目名称,选取“添加”,然后选取“新建文件夹”。
将新文件夹重命名为 account。
右键单击 account 文件夹,选取“添加”,然后选取“新建项...”****
在“添加新项”对话框中,转至“已安装”>“JavaScript”>“Windows 应用商店”,然后选取“页面控制”。
在“名称”****字段中,键入 "account.html",然后单击“添加”。
修改应用的新文件。
在 account.html 文件中,将 <div> 元素替换为以下代码。
<div id="account" data-win-control="WinJS.UI.SettingsFlyout" data-win-options="{width: 'narrow'}"> <div class="SettingsPane"> <div class="win-label"> <button onclick="WinJS.UI.SettingsFlyout.show()" class="win-backbutton"> </button> <span class="SettingsTitle">Account</span> </div> <article class="SettingsContent"> <p id="accountPrompt"></p> </article> <div> <!-- define one button to sign in and another to sign out, but show only --> <!-- one at a time, depending on whether the user is currently signed in or not. --> <button id="signInBtn" onclick="signInCmd()" style="display: none">Sign in</button> <button id="signOutBtn" onclick="signOutCmd()" style="display: none">Sign out</button> </div> </div> </div>
将以下代码添加到 account.css 文件的末尾。
.account p { margin-left: 120px; } .SettingsPane { margin-top:36px; margin-left:48px; } .SettingsTitle { margin-left: 36px; } .SettingsContent { margin-top: 24px; } #account { background-color: gray ; }
创建“隐私”****弹出窗口页面。
为“隐私”弹出窗口文件创建新文件夹。在“解决方案资源管理器”中****,右键单击项目名称,选取“添加”,然后选取“新建文件夹”****。
将新文件夹重命名为 privacy。
右键单击 privacy 文件夹,选取“添加”,然后选取“新建项...”****
在“添加新项”对话框中,转至“已安装”>“JavaScript”>“Windows 应用商店”,然后选取“页面控制”。
在“名称”****字段中,键入 "privacy.html",然后单击“添加”。
修改应用的新文件。
在 privacy.html 文件中,将 <div> 元素替换为以下代码。
<div id="privacy" data-win-control="WinJS.UI.SettingsFlyout" data-win-options="{width: 'narrow'}"> <div class="SettingsPane"> <div class="win-label"> <button onclick="WinJS.UI.SettingsFlyout.show()" class="win-backbutton"> </button> <span class="SettingsTitle">Privacy</span> </div> <article class="SettingsContent"> <!-- Customize this text to fit your application. --> <h2>How we protect your personal information</h2> <h4>Your privacy statement or a link to your privacy statement goes here.</h4> </article> </div> </div>
确保更改 privacy.html 的内容,以便让它指向你的隐私声明。
将以下代码添加到 account.css 文件的末尾。
.privacy p { margin-left: 120px; } .SettingsPane { margin-top:36px; margin-left:48px; } .SettingsTitle { margin-left: 36px; } .SettingsContent { margin-top: 24px; } #privacy { background-color: gray ; }
添加设置命令。
在 default.js 文件中,将以下代码添加到 app.onactivated 事件处理程序。
// Define the Settings flyout commands. // The commands appear in the Settings charm from top-to-bottom // in the order they are added. app.onsettings = function (e) { e.detail.applicationcommands = { // Add the Account command "account": { // Location of page content href: "/account/account.html", // Command to show in settings menu title: "Account" }, // Add the privacy command. "privacy": { // Location of page content href: "/privacy/privacy.html", // Command to show in settings menu title: "Privacy" } } // Command to update app's settings menu // using the preceding definition. WinJS.UI.SettingsFlyout.populateSettings(e); }
构建并运行你的应用。
打开“设置”超级按钮。确认“帐户”和“隐私”****命令已显示在“设置”窗格中。
单击每个命令以确认它将打开弹出窗口。
在看到两个弹出窗口后,关闭你的应用并继续操作。
步骤 4: 添加 UI 内容和数据绑定
你需要让你的应用 UI 表示它所连接的用户 Microsoft 帐户的当前状态。使用数据绑定,以便 UI 内容会随着相应数据值的更改而更改,而不是在应用的 UI 中放置静态文本。
在此步骤中,你将添加将应用数据连接到 UI 的代码。
更新 default.html,以使包含的 UI 元素具有将 UI 连接到应用数据的绑定属性。
为此,请将 default.html 中 <body> 标记的内容替换为以下代码。
<div id="bindingDiv"> <!-- The elements in this div get their data from the app's data object by using a binding object. --> <div class="heading"> <h1> <!-- The app's title. This is configured by the program. --> <span id="titleText" data-win-bind="innerText: person.titleText">person.titleText</span> </h1> </div> <div class="content"> <!-- The app's content. This is a photo for this example. When the user is signed out, one photo is shown; when they are signed in, another is shown. --> <img id="appImage" data-win-bind="src: image.url; title: image.caption" /> <!-- Show the caption as text in the display as well as hover text in the image. --> <p id="appImageCaption" data-win-bind="innerText: image.caption">image.caption</p> </div> </div>
在具有 data-win-bind 属性的标记中,绑定到属性的数据字段也将显示在标记值中。这样做只是为了进行调试。如果绑定成功,则程序中的数据值将替换此文本。如果绑定不成功,你将看到不会显示在 UI 中的数据值的名称,这样可以帮助你调试错误。
创建要用作绑定对象的数据对象。
在你的项目的 js 文件夹中创建一个称为 data.js 的新文件,并向其中添加代码。执行此操作的步骤:
在“解决方案资源管理器”中,右键单击 js 文件夹,然后依次选择“添加”和“新建项...”。****
转至“已安装”>“JavaScript”>“代码”,然后选取“JavaScript 文件”。
在“名称”****字段中,键入 "data.js",然后单击“添加”。
将 data.js 的内容替换为以下示例中的代码。
(function () { "use strict"; // The global data object used to reference the binding object WinJS.Namespace.define("binding", { Person: null } ); // Static text WinJS.Namespace.define("display", { state: ["Some nice photo", "'s favorite photo"] } ); // The app's data object that is used to map the // sign-in state to the UI. WinJS.Namespace.define("appInfo", { index: 0, // The sign-in state. image: { // The image to show url: "/images/SignedOutImage.png", caption: "Something not so special." }, person: { // The info about the user userName: null, titleText: display.state[0] } } ); })();
通过在引用 default.js 的 <script> 标记前输入以下代码,在 default.html 中添加对此新文件的引用。
<!-- The app's data definition --> <script src="/js/data.js"></script>
添加代码以将数据对象绑定到 UI。
在 default.js 的 app.onactivated 事件处理程序中,添加以下代码以创建并初始化绑定对象。
// Create the binding object that connects the appInfo data // to the app's UI. binding.Person = WinJS.Binding.as(appInfo); // Update the binding object so that it reflects the state // of the app and updates the UI to reflect that state. getInfoFromAccount(binding.Person);
添加一个事件处理程序,以便在加载应用文档后使用绑定对象中的数据更细 UI。
在 default.js 中,将此事件处理程序添加到紧靠 app.oncheckpoint 任务之前。
app.onloaded = function (args) { // Initialize the UI to match the corresponding data object. var div = document.getElementById("bindingDiv"); WinJS.Binding.processAll(div, appInfo); }
添加将应用数据与用户数据进行同步的函数。
对于这个步骤,此函数只提供用于测试的静态数据。将在稍后的步骤中添加从 Microsoft 帐户获取用户数据的函数。
在 default.js 中,将此函数添加到异步函数后,以便可以在应用的其他模块中看到它。
function getInfoFromAccount(p) { // Test for a parameter and assign the unbound data object // if a parameter wasn't passed. This doesn't refresh the binding // object, but it does keep the data object coherent with the // sign-in state. if (undefined === p) { p = appInfo; } if (0 == p.index) { // The program executes this branch when the user is // not signed in. // Set the data to the signed-out state values // and update the app title. p.person.userName = null; p.person.titleText = display.state[p.index]; // These elements are the default values to show // when the user is not signed in. p.image.url = "/images/SignedOutImage.png"; p.image.caption = "Something not so special."; } if (1 == p.index) { // The program executes this branch when the user is // signed in. // Set the data to the signed-in state, // get the user's first name, and update the app title. p.person.userName = "Bob"; p.person.titleText = p.person.userName + display.state[p.index]; // These elements would normally be read from the user's data, // but in this example, app resources are used. p.image.url = "/images/SignedInImage.png"; p.image.caption = "Something special to me."; } }
添加图像文件。
将两个图像文件复制到你的项目的 images 文件夹。将一个图像重命名为 "SignedOutImage.png",将另一个图像重命名为 "SignedInImage.png"。
在“解决方案资源管理器”中,右键单击 images 文件夹,然后选择“添加”>“现有项...”****。
选择刚刚添加的两个图像文件,然后单击“添加”。
构建并测试你的应用。如果它在页面中显示正确的文本和 SignedOutImage.png 图像,请继续执行下一步。
如果你的应用显示数据字段的名称而不是文本,则表明数据绑定存在问题,你需要修复才能继续操作。
步骤 5: 更新“帐户”弹出窗口以使用绑定对象
在 account.html 中,将 <button> 标记更改为如下所示,以便使用登录状态在弹出窗口中显示正确的按钮。
<button id="signInBtn" onclick="signInCmd(binding.Person)" style="display:none">Sign in</button> <button id="signOutBtn" onclick="signOutCmd(binding.Person)" style="display:none">Sign out</button>
在 account.js 中,将以下这些函数添加到异步函数后。
function updateDisplay(p) { // Update the display to show the caption text and button // that apply to the current sign-in state. // Test for a parameter and assign the unbound global data object // if a parameter wasn't passed. This doesn't refresh the screen // but it does keep the data object coherent. if (undefined === p) { p = appInfo; } // Get the elements in the display for this function to update. var prompt = document.getElementById("accountPrompt"); var inBtn = document.getElementById("signInBtn"); var outBtn = document.getElementById("signOutBtn"); // Update the elements to show the correct text and button for the // the sign-in state. if (0 == p.index) { // The user is signed out, so prompt them to sign in. prompt.innerText = "Sign in to see your favorite photo." outBtn.style.display = "none"; inBtn.style.display = "block"; } else { // The user is signed in so welcome them and show the sign-out button. prompt.innerText = "Welcome, " + p.person.userName + "!" inBtn.style.display = "none"; outBtn.style.display = "block"; } } function signInCmd(p) { // Sign the new user in. // This call closes the Flyout and Settings charm. SignInNewUser(p); // Update the display to the signed-in state but keep the Flyout open // in case they want to sign in again. updateDisplay(p); // Return to the Settings flyout. WinJS.UI.SettingsFlyout.show(); } function signOutCmd(p) { // Sign the current user out. SignOutUser(p); // Update the display to the signed-out state but keep the Flyout open // in case they want to sign in again. updateDisplay(p); // Return to the Settings flyout. WinJS.UI.SettingsFlyout.show(); }
然后,修改 WinJS.UI.Pages.define 调用的 ready 情况的函数,以使它包含对 updateDisplay 的调用,如以下示例所示。
ready: function (element, options) { // TODO: Initialize the page here. // Update the Account Flyout to reflect // the user's current sign-in state. updateDisplay(binding.Person); },
向 default.js 中添加实现用户登录和注销 Microsoft 帐户的函数。
这些函数尚未与 Windows Live 服务功能—进行交互目前。将在稍后的步骤中添加该交互。这些函数只是让你能够测试绑定对象,以确保它在登录状态下可以正常发挥作用,并且当登录状态更改时会更新 UI。
function SignInNewUser(p) { // Sign the user in. // Test for a parameter and assign the unbound global data object // if a parameter wasn't passed. This doesn't refresh the screen // but it does keep the data object coherent. if (undefined === p) { p = appInfo; } p.index = 1; getInfoFromAccount(p); } function SignOutUser(p) { // Sign the user out. // Test for a parameter and assign the unbound global data object // if a parameter wasn't passed. This doesn't refresh the screen // but it does keep the data object coherent. if (undefined === p) { p = appInfo; } p.index = 0; getInfoFromAccount(p); }
构建并测试你的应用。
你的应用启动并显示 SignedOutImage.png。
打开“设置”超级按钮并选择“帐户”命令。确认已显示“登录”****按钮和提示。
单击“登录”按钮并确认应用状态和“帐户”弹出窗口内容发生更改以反映登录状态。
在“帐户”****弹出窗口中,确认已显示“注销”按钮和提示。
单击“注销”****按钮并确认应用状态和“帐户”弹出窗口内容发生更改以反映注销状态。
如果你的应用如此运行,便可以准备添加 Windows Live 服务功能了。
步骤 6: 添加 Live SDK 函数
向你的应用中添加对 Live SDK 的引用。
在“解决方案资源管理器”中,右键单击“引用”****,然后选取“添加引用...”。
转至“Windows”>“扩展”,选中“Live SDK”,然后单击“确定”。
在 default.html 的 <head> 标记中,在 default.css 链接前添加以下行。
<!-- The Live SDK --> <script src="///LiveSDKHTML/js/wl.js"></script>
初始化 Live SDK。
在 default.js 中,在 app.onactivated 处理程序中的 binding.Person 任务后输入以下代码。
// Initialize the Live SDK. WL.init();
更新 getInfoFromAccount 函数,以便你的应用从 Microsoft 帐户获取用户的登录状态。
在 default.js 的 getInfoFromAccount 中,将测试 p.index 的两个 if 语句替换为以下代码。
// Call the user's Microsoft account to get the identity of the current // user. If the user is signed in, the success branch runs. // If the user is not signed in, the failure branch runs. WL.api({ path: "me", method: "GET" }).then( function (response) { // The program executes this branch when the user is // signed in. // Save the app's sign-in state. p.index = 1; // Set the data to the signed-in state, // get the user's first name, and update the app title. p.person.userName = response.first_name; p.person.titleText = p.person.userName + display.state[p.index]; // These elements would normally be read from the user's data, // but in this example, app resources are used. p.image.url = "/images/SignedInImage.png"; p.image.caption = "Something special to me."; }, function (responseFailed) { // The program executes this branch when the user is // not signed in. // Reset the app state. p.index = 0; // Set the data to the signed-out state values // and update the app title. p.person.userName = null; p.person.titleText = display.state[p.index]; // These elements are the default values to show // when the user is not signed in. p.image.url = "/images/SignedOutImage.png"; p.image.caption = "Something not so special."; } );
更新 SignInNewUser 函数以实现用户登录其 Microsoft 帐户。
在 default.js 的 SignInNewUser 中,将参数测试后的代码替换为以下代码。
// Sign the user in with the minimum scope necessary for the app. WL.login({ scope: ["wl.signin"] }).then(function (response) { getInfoFromAccount(p); });
更新 SignOutUser 函数。
在 default.js 的 SignOutUser 中,将参数测试后的代码替换为以下代码。
// Sign out and then refresh the app's data object. WL.logout().then(function (response) { getInfoFromAccount(p); });
添加 ShowSignOutButton 函数。
在 default.js 末尾,添加如下所示的 ShowSignOutButton 函数。
function ShowSignOutButton() { // Return true or false to indicate whether the user // can sign out of the app. return (WL.canLogout()); }
添加验证用户是否可以注销的测试。如果用户从与 Microsoft 帐户关联的某个计算机帐户登录到其应用,则用户无法注销其应用。此函数针对这种情况进行测试,以便向用户显示正确的提示。
在 account.js 的 updateDisplay 函数中,将 if 语句替换为以下代码。请注意添加的测试,以便区别是否应显示“注销”按钮。
if (0 == p.index) { // The user is signed out, so prompt them to sign in. prompt.innerText = "Sign in to see your favorite photo." outBtn.style.display = "none"; inBtn.style.display = "block"; } else { // The user is signed in, so welcome them. // If the user can sign out, show them the sign-out button. var promptText = "Welcome, " + p.person.userName + "!"; var signOutBtnStyle = "block"; if (ShowSignOutButton()) { // The user is signed in and can sign out later, // so welcome them and show the sign-out button. signOutBtnStyle = "block"; } else { // The user is signed in and can't sign out later, // so welcome them and hide the sign-out button. promptText = promptText + " The app is signed in through your Windows 8 account." signOutBtnStyle = "none"; } prompt.innerText = promptText; outBtn.style.display = signOutBtnStyle; inBtn.style.display = "none" }
删除为之前的测试使用的虚拟代码。
在 account.js 的 signInCmd 中,删除对 updateDisplay 和 WinJS.UI.SettingsFlyout.show 的调用,以便使该函数中只有以下行。
// Sign the new user in. // This call closes the Flyout and Settings charm. SignInNewUser(p);
在 account.js 的 signOutCmd 中,删除对 updateDisplay 的调用,以便使该函数中只有以下行。
// Sign the current user out. SignOutUser(p); // Return to the Settings flyout. WinJS.UI.SettingsFlyout.show();
现在,你的应用已准备好进行 Microsoft 帐户测试了。
步骤 7: 测试你的应用
构建并运行你的应用,然后这些操作。
测试登录到 Microsoft 帐户。
从应用从用户 Microsoft 帐户注销的状态开始,尝试执行以下步骤:
- 打开“设置”浮出控件,选择“帐户”命令,然后单击“登录”****。
- 使用 Microsoft 帐户登录。如果应用提示你是否允许继续操作,单击“是”。
- 验证应用中的文本和图片是否已更改为登录文本和图片。
测试从应用注销。
注意 如果你正在从与 Microsoft 帐户关联的计算机帐户测试应用,将禁用“注销”按钮。这是预期行为。要运行此测试,你必须从未与 Microsoft 帐户关联的计算机帐户运行应用。
从应用登录到用户 Microsoft 帐户的状态开始,尝试执行以下步骤:
- 打开“设置”浮出控件,选择“帐户”****命令,然后单击“注销”。
- 验证应用中的文本和图片是否已更改为注销文本和图片。
测试单一登录。
单一登录是 Windows 的一项功能,它让你可以将你的计算机帐户与 Microsoft 帐户相关联。如果你正在以这样一个计算机帐户运行应用,则应用的行为将与上面所述的情况不同。
例如:
- 应用可能会以登录状态自动启动。
- “注销”****按钮不会显示在“帐户”弹出窗口中,因为你无法在应用中从你的帐户注销。
- “帐户”弹出窗口会显示其他消息,说明你无法从应用中注销。