How to add Microsoft services to your app (HTML)
You can find out here how to add features from Microsoft services to your Windows Runtime app so it can access a user's profile info, files and photos in his or her Microsoft OneDrive, and Outlook.com info. The steps in this tutorial start with an empty app and add the features to sign in to a user's Microsoft account and get the user's profile info to display it in the app.
Important The tutorial in this topic demonstrates a Windows Store app. You can also add Microsoft services to a Windows Phone Store app. Since the Windows Phone user interface does not support flyouts, however, you have to use pages in a Windows Phone Store app to implement the features for which flyouts are used in this topic.
What you need to know
Technologies
Prerequisites
- Windows 8
- Microsoft Visual Studio
- The Live SDK
- A Windows Store developer account
- Two image files (PNG format) to use in your app
Instructions
Step 1: Create a Blank App project and include the Live SDK
Create your new app from a Visual Studio template by doing this:
- From Visual Studio, in the File menu, click New Project...
- In the New Project... dialog box, go to Installed > Templates > JavaScript > Windows Store.
- Select Blank App.
- Enter the name and location for your new app, and click OK.
- Build and test your app. It should start and show a blank page that displays only "Content goes here". If you see this, close your app and continue.
Step 2: Add the app to your Windows Store developer account
For your app to use the cloud services that the Live SDK accesses, it must be registered in your Windows Store developer account. You don't need to submit your app to the Windows Store for certification. You just need to enter a name for it in your Windows Store developer account.
Step 3: Add the app data and Settings flyouts
A Windows Store app that uses the Live SDK must do at least these two things:
- Allow the user to sign in to their Microsoft account, and sign out, if that's possible.
- Display a privacy policy that describes how you'll protect the personal data that your app will access.
For more info about the sign-in and sign-out experience and the privacy policy, see the Requirements for Microsoft account sign-in.
In a Windows Store app, these are accessed through the Settings flyouts.
To add Flyouts to your app, do this:
Create the Account Flyout page.
Create a new folder for the Account Flyout files. In the Solution Explorer, right-click the project name, pick Add, and pick New Folder.
Rename the new folder to account.
Right-click the account folder, pick Add, and pick New Item...
In the Add New Item dialog box, go to Installed > JavaScript > Windows Store, and pick Page Control.
In the Name field, type "account.html" and click Add.
Modify the new files for your app.
In the account.html file, replace the <div> element with this code.
<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>
Add the following code to the end of the account.css file.
.account p { margin-left: 120px; } .SettingsPane { margin-top:36px; margin-left:48px; } .SettingsTitle { margin-left: 36px; } .SettingsContent { margin-top: 24px; } #account { background-color: gray ; }
Create the Privacy Flyout page.
Create a new folder for the Privacy Flyout files. In the Solution Explorer, right-click the project name, pick Add, and pick New Folder.
Rename the new folder to privacy.
Right-click the privacy folder, pick Add, and pick New Item...
In the Add New Item dialog box, go to Installed > JavaScript > Windows Store, and pick Page Control.
In the Name field, type "privacy.html", and click Add.
Modify the new files for your app.
In the privacy.html file, replace the <div> element with this code.
<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>
Be sure to change the content of privacy.html so that it refers to your privacy statement.
Add the following code to the end of the account.css file.
.privacy p { margin-left: 120px; } .SettingsPane { margin-top:36px; margin-left:48px; } .SettingsTitle { margin-left: 36px; } .SettingsContent { margin-top: 24px; } #privacy { background-color: gray ; }
Add the settings commands.
In the default.js file, add this code to the app.onactivated event handler.
// 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); }
Build and run your app.
Open the Settings charm. Verify that the Account and Privacy commands appear in the Settings pane.
Click on each command to verify it opens a Flyout.
After you've seen both Flyouts, close your app and continue.
Step 4: Add the UI content and data binding
You'll want your app's UI to represent the current state of its connection to the user's Microsoft account. Instead of placing static text in your app's UI, use data binding so the UI content changes when its corresponding data value changes.
In this step, you add the code that connects your app's data to the UI.
Update default.html to include the UI elements with the binding attributes that connect the UI to app data.
To do this, replace the contents of the <body> tag in default.html with this code.
<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>
In the tags with data-win-bind attributes, the data field that is bound to an attribute also appears in the tag's value. This is done just for debugging. If the binding is successful, the data values from the program replace this text. If the binding isn't successful, you see the name of the data value that is not being shown in the UI, which can help you debug the error.
Create the data object to use as a binding object.
Create a new file called data.js in the js folder of your project and add code to it. To do this:
In the Solution Explorer, right click on the js folder, and select Add, and then New Item...
Go to Installed > JavaScript > Code, and then pick JavaScript file.
In the Name field, type "data.js" and then click Add.
Replace the contents of data.js with the code in this example.
(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] } } ); })();
Add the reference to this new file in default.html by entering this code before the <script> tag that references default.js.
<!-- The app's data definition --> <script src="/js/data.js"></script>
Add the code to bind the data object to the UI.
In default.js, in the app.onactivated event handler, add this code to create the binding object and initialize it.
// 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);
Add an event handler to update the UI with the data from the binding object after the app's document has been loaded.
In default.js, add this event handler just before the app.oncheckpoint assignment.
app.onloaded = function (args) { // Initialize the UI to match the corresponding data object. var div = document.getElementById("bindingDiv"); WinJS.Binding.processAll(div, appInfo); }
Add the function that will sync the app's data with the user's data.
For this step, this function just provides static data for testing. The functions to get the user's data from their Microsoft account will be added in a later step.
In default.js, add this function after the anonymous function so that it will be visible to other modules in the app.
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."; } }
Add your image files.
Copy the two image files to the images folder in your project. Rename one image as "SignedOutImage.png" and the other one as "SignedInImage.png".
In the Solution Explorer, right-click the images folder and select Add > Existing Item...
Select the two image files that you just added and then click Add.
Build and test your app. If it shows the correct text and the SignedOutImage.png image in the page, continue to the next step.
If your app shows the name of the data field instead of the text, there's a problem with the data binding that you'll need to fix before you continue.
Step 5: Update the Account Flyout to use the binding object
In account.html, change the <button> tags to look like this, so the sign-in state is used to display the correct button in the Flyout.
<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>
In account.js, add these functions after the anonymous function.
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(); }
Then, modify the function of the ready case of the WinJS.UI.Pages.define call so that it includes a call to updateDisplay as in this example.
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); },
Add the functions to default.js that sign the user in and out of their Microsoft account.
These functions don't interact with the Windows Live Services features—yet. That will be added in a later step. These functions just enable you to test the binding object to make sure it works in both sign-in states and updates the UI when the sign-in state changes.
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); }
Build and test your app.
Your app starts and displays SignedOutImage.png.
Open the Settings charm and select the Account command. Verify that the Sign in button and prompt appear.
Click the Sign in button and verify that the app state and the Account Flyout content change to reflect the signed-in state.
In the Account Flyout, verify that the Sign out button and prompt appear.
Click the Sign out button and verify that the app state and the Account Flyout content change to reflect the signed-out state.
When your app works like this, you're ready to add the Windows Live Services features.
Step 6: Add the Live SDK functions
Add the reference to the Live SDK to your app.
In the Solution Explorer, right-click References and pick Add Reference...
Go to Windows > Extensions, check Live SDK, and then click OK.
In the <head> tag of default.html, add this line before the default.css link.
<!-- The Live SDK --> <script src="///LiveSDKHTML/js/wl.js"></script>
Initialize the Live SDK.
In default.js, enter this code after the binding.Person assignment in the app.onactivated handler.
// Initialize the Live SDK. WL.init();
Update the getInfoFromAccount function so that your app gets the user's sign-in state from their Microsoft account.
In default.js, in getInfoFromAccount, replace the two if statements that test p.index with this code.
// 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."; } );
Update the SignInNewUser function to sign the user in to their Microsoft account.
In default.js, in SignInNewUser, replace the code after the parameter test with this code.
// Sign the user in with the minimum scope necessary for the app. WL.login({ scope: ["wl.signin"] }).then(function (response) { getInfoFromAccount(p); });
Update the SignOutUser function.
In default.js, in SignOutUser, replace the code after the parameter test with this code.
// Sign out and then refresh the app's data object. WL.logout().then(function (response) { getInfoFromAccount(p); });
Add the ShowSignOutButton function.
At the end of default.js, add the ShowSignOutButton function shown here.
function ShowSignOutButton() { // Return true or false to indicate whether the user // can sign out of the app. return (WL.canLogout()); }
Add the test for whether the user can sign out. If the user signs in to their app from a computer account that is associated with a Microsoft account, he or she cannot sign out of their app. This function tests for this condition so the correct prompt can be displayed to the user.
In account.js, in the updateDisplay function, replace the if statement with this code. Notice the test that was added to tell whether the Sign out button should be displayed.
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" }
Remove the dummy code used for earlier testing.
In account.js, in signInCmd, remove the calls to updateDisplay and WinJS.UI.SettingsFlyout.show so that the only line of code in that function is this one.
// Sign the new user in. // This call closes the Flyout and Settings charm. SignInNewUser(p);
In account.js, in signOutCmd, remove the call to updateDisplay so that the only lines of code in that function are these.
// Sign the current user out. SignOutUser(p); // Return to the Settings flyout. WinJS.UI.SettingsFlyout.show();
Your app is now ready for testing with a Microsoft account.
Step 7: Test your app
Build and run your app and test these actions.
Test signing in to a Microsoft account.
Starting with the app signed out from the user's Microsoft account, try these steps:
- Open the Settings flyout, select the Account command, and click Sign in.
- Sign in with a Microsoft account. If the app prompts you for permission to continue, click Yes.
- Verify that the text and picture in the app change to the signed-in text and picture.
Test signing out from the app.
Note If you are testing your app from a computer account that is associated with a Microsoft account, the Sign out button will be disabled. This is the expected behavior. To run this test, you must run your app from a computer account that is not associated with a Microsoft account.
Starting with the app signed in to the user's Microsoft account, try these steps:
- Open the Settings flyout, select the Account command and click Sign out.
- Verify that the text and picture in the app change to the signed-out text and picture.
Test single sign-on.
Single sign-on is the feature of Windows that lets you associate your computer account with your Microsoft account. If you're running your app from such a computer account, the app behaves differently from what is described above.
For example:
- The app could start in the signed-in state, automatically.
- The Sign out button doesn't appear in the Account Flyout, because you can't sign out from your account from within the app.
- The Account Flyout shows an additional message saying that you can't sign out from your app.