Request for IOS and Android devs: Packaging and Publishing Experiences

The Visual Studio team is looking for Android and iOS developers who can provide feedback on app packaging and publishing experiences. This survey can take as little as 5 minutes to complete and will provide direct feedback to support changes in future versions of Visual Studio.

 

The information you provide is entirely voluntary. If you do not wish to provide us with any information, please disregard this survey. By filling out and returning this survey, you agree that we can use, disclose, reproduce, or otherwise distribute your feedback at the aggregated level. Your personal information will remain confidential. Please check http://privacy.microsoft.com/en-us/default.aspx for Microsoft Privacy Statements.

 

Use this url: https://illumeweb.smdisp.net/collector/Survey.ashx?Name=PackagePublish

Authentication using Facebook, Google and Microsoft accounts in Universal Apps using MVVM

Introduction

This sample shows how to connect universal apps to Facebook, Google and Microsoft accounts using the MVVM pattern.

Building the Sample

You only need Visual Studio 2012 or Visual Studio 2013 and Windows 8 or Windows 8.1, both the RTM version.

Description

Recently published was Authentication using Facebook, Google and Microsoft account in WP8.0 App (MVVM) and this sample has the same goal, but now the target is Universal Apps. Both have the goal to use the MVVM pattern.

Before starting this sample, analize to see if the SDKs used in the first sample could be used in this new sample and in a first attempt didn´t find a package for all the targets (Windows 8.1 and Windows Phone 8.1 Runtime). Let’s see that analysis.

The packages used was:

  1. Facebook SDK for Windows Phone (http://facebooksdk.net/docs/phone/ )
  2. Google APIs Auth Client and Google APIs OAuth2 Client (https://www.nuget.org/packages/Google.Apis.Auth/ andhttps://www.nuget.org/packages/Google.Apis.Authentication/1.6.0-beta )
  3. Live SDK (http://msdn.microsoft.com/en-US/onedrive/dn630256 )

The packages that were analized are:

  1. Facebook SDK for Windows Phone: there is a package for Windows 8.1 Store Apps but there isn’t for Windows Phone 8.1 Runtime (we cannot use the version from Windows Phone 8.0 because it uses a namespace for controls that does not exist in the Windows Phone 8.1 Runtime)
  2. Google APIs Auth Client and Google APIs OAuth2 Client: there is a package compatible with Windows 8.1 Store Apps but it is a bit different from the sample created before, the API changed. And there isn’t a package for the Windows Phone 8.1 Runtime.
  3. Live SDK: is compatible with the Windows Phone 8.1 Runtime and Windows 8.1.

The next step, was to try to port the package for Google from Windows 8.1 Store Apps to Windows Phone 8.1 Runtime, create the logic because there is a lot of code shared between them and then the hard work began.

After some attempts, the code started to throw the exception NotImplementedException because theWebAuthenticationBroker class does not work the same way for these targets. There is a sample that shows this difference, here is the source code  and we will see this in this sample.

In conclusion of this analysis, I decided to use WebAuthenticationBroker for authentication using Facebook and Google accounts and Live SDK for Microsoft accounts.

Let’s start the sample!

Note: This sample uses MVVM Light and Cimbalino Toolkit.

For each provider it is necessary to get the app id/client id/client secrect in their websites.

For Google go to https://console.developers.google.com/project and create a new project (APIs and auth > credentials).

Universal Apps using MVVM

For Facebook go to https://developers.facebook.com/ and create a new app.

For Live SDK go to https://account.live.com/developers/applications/index and create one or use an existing app.

Before you start you should change the Constant file to add client ids / client secret / app id, without it the app fails!!

 

/// <summary>   
    /// Defines the constants strings used in the app.   
    /// </summary>   
    public class Constants   
    {   
        /// <summary>   
        /// The google callback url.   
        /// </summary>   
        public const string GoogleCallbackUrl = "urn:ietf:wg:oauth:2.0:oob";   
   
        /// <summary>   
        /// The facebook app id.   
        /// </summary>   
        public const string FacebookAppId = "<app id>";   
   
        /// <summary>   
        /// The google client identifier.   
        /// </summary>   
        public const string GoogleClientId = "<client id>";   
           
        /// <summary>   
        /// The google client secret.   
        /// </summary>   
        public const string GoogleClientSecret = "<client secret";   
   
        /// <summary>   
        /// The login token.   
        /// </summary>   
        public const string LoginToken = "LoginToken";   
           
        /// <summary>   
        /// The facebook provider.   
        /// </summary>   
        public const string FacebookProvider = "facebook";   
   
        /// <summary>   
        /// The google provider.   
        /// </summary>   
        public const string GoogleProvider = "google";   
   
        /// <summary>   
        /// The microsoft provider.   
        /// </summary>   
        public const string MicrosoftProvider = "microsoft";   
    }

This sample will use the same idea used in Authentication using Facebook, Google and Microsoft account in WP8.0 App (MVVM). There are classes that have the same goal and the same name. Like in that sample, this sample created a SessionService that manages the Login and Logout using a provider value. That is nice because in LoginView we set the buttons to the same command and for each command we set the provider in commandparameter. With it, the LoginView and LoginViewModel are more clear and simple.

The following are the classes created:

  • FacebookService has all code related with authentication with Facebook account;
  • MicrosoftService has all code related with authentication with Microsoft account;
  • GoogleService has all code related with authentication with Google account;
  • SessionService call the methods login or logout for the provide requested;

The Flow

To help to understood the difference in the flow in each platform some diagrams were created.

The flow for the Windows 8.1 Store apps will be:

The flow for Windows Phone 8.1 Runtime will be:

  • using Microsoft account
  • using Facebook Account or Google account

Note: Start in LoginView using the blue arrow and when the blue flow finnishes, go to FacebookService/GoogleService and follow the red flow.

Like we can see, the authentication for Windows Phone 8.1 is very complicated, it could be easier like in Windows 8.1 Store apps. And It breaks the MVVM Pattern!

This sample is a Universal App, for this reason the code can be found in the Shared Project and to add specific features for each target directives (#if #else #endif) are used, it can cause some difficulties for understanding the code but is a good way to have only one code in one place. Partial methods and classes can be used here, because in most cases directives are added to add a method for Windows Phone.

The FacebookService

/// <summary>   
    /// Defines the Facebook Service.   
    /// </summary>   
    public class FacebookService : IFacebookService   
    {   
        private readonly ILogManager _logManager;   
   
        /// <summary>   
        /// Initializes a new instance of the <see cref="FacebookService"/> class.   
        /// </summary>   
        /// <param name="logManager">   
        /// The log manager.   
        /// </param>   
        public FacebookService(ILogManager logManager)   
        {   
            _logManager = logManager;   
        }   
   
        /// <summary>   
        /// The login sync.   
        /// </summary>   
        /// <returns>   
        /// The <see cref="Task"/> object.   
        /// </returns>   
        public async Task<Session> LoginAsync()   
        {   
            const string FacebookCallbackUrl = "https://m.facebook.com/connect/login_success.html";   
            var facebookUrl = "https://www.facebook.com/dialog/oauth?client_id=" + Uri.EscapeDataString(Constants.FacebookAppId) + "&redirect_uri=" + Uri.EscapeDataString(FacebookCallbackUrl) + "&scope=public_profile,email&display=popup&response_type=token";   
   
            var startUri = new Uri(facebookUrl);   
            var endUri = new Uri(FacebookCallbackUrl);   
  
#if WINDOWS_PHONE_APP   
            WebAuthenticationBroker.AuthenticateAndContinue(startUri, endUri, null, WebAuthenticationOptions.None);   
            return null;   
#else   
            var webAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, startUri, endUri);   
            return GetSession(webAuthenticationResult);   
#endif   
        }   
           
        private void GetKeyValues(string webAuthResultResponseData, out string accessToken, out string expiresIn)   
        {   
            string responseData = webAuthResultResponseData.Substring(webAuthResultResponseData.IndexOf("access_token", StringComparison.Ordinal));   
            string[] keyValPairs = responseData.Split('&');   
            accessToken = null;   
            expiresIn = null;   
            for (int i = 0; i < keyValPairs.Length; i++)   
            {   
                string[] splits = keyValPairs[i].Split('=');   
                switch (splits[0])   
                {   
                    case "access_token":   
                        accessToken = splits[1];   
                        break;   
                    case "expires_in":   
                        expiresIn = splits[1];   
                        break;   
                }   
            }   
        }   
   
        /// <summary>   
        /// This function extracts access_token from the response returned from web authentication broker   
        /// and uses that token to get user information using facebook graph api.    
        /// </summary>   
        /// <param name="accessToken">   
        /// The access Token.   
        /// </param>   
        /// <returns>   
        /// The <see cref="Task"/>.   
        /// </returns>   
        private async Task<UserInfo> GetFacebookUserNameAsync(string accessToken)   
        {   
            var httpClient = new HttpClient();   
            var response = await httpClient.GetStringAsync(new Uri("https://graph.facebook.com/me?access_token=" + accessToken));   
            var value = JsonValue.Parse(response).GetObject();   
            var facebookUserName = value.GetNamedString("name");   
   
            return new UserInfo   
            {   
                Name = facebookUserName,   
            };   
        }   
   
        /// <summary>   
        /// Logouts this instance.   
        /// </summary>   
        public async void Logout()   
        {   
            Exception exception = null;   
            try   
            {   
                  
            }   
            catch (Exception ex)   
            {   
                exception = ex;   
            }   
            if (exception != null)   
            {   
                await _logManager.LogAsync(exception);   
            }   
        }   
  
#if WINDOWS_PHONE_APP   
        public async Task<Session> Finalize(WebAuthenticationBrokerContinuationEventArgs args)   
        {   
            Exception exception = null;   
            try   
            {   
                var result = args.WebAuthenticationResult;   
   
                return GetSession(result);   
            }   
            catch (Exception e)   
            {   
                exception = e;   
            }   
   
            await _logManager.LogAsync(exception);   
              
            return null;   
        }   
#endif   
        private Session GetSession(WebAuthenticationResult result)   
        {   
            if (result.ResponseStatus == WebAuthenticationStatus.Success)   
            {   
                string accessToken;   
                string expiresIn;   
                GetKeyValues(result.ResponseData, out accessToken, out expiresIn);   
   
                return new Session   
                {   
                    AccessToken = accessToken,   
                    ExpireDate = new DateTime(long.Parse(expiresIn)),   
                    Provider = Constants.FacebookProvider   
                };   
            }   
            if (result.ResponseStatus == WebAuthenticationStatus.ErrorHttp)   
            {   
                throw new Exception("Error http");   
            }   
            if (result.ResponseStatus == WebAuthenticationStatus.UserCancel)   
            {   
                throw new Exception("User Canceled.");   
            }   
            return null;   
        }   
    }

In this class, in LoginAsync, we could see the directives that define the code for each platform. The first attempt was a bit complicated to define a solution for it, using null was the solution (for Windows Phone, of course!). This class doesn´t do anything in the logout method, we could remove it, but to keep the same pattern in all the classes it wasn´t removed and the session is not saved in webview, at least it is possible to login using a different account when the LoginView is shown again.

The GoogleService

/// <summary>   
    /// The google service.   
    /// </summary>   
    public class GoogleService : IGoogleService   
    {   
        private readonly ILogManager _logManager;   
   
        /// <summary>   
        /// Initializes a new instance of the <see cref="GoogleService"/> class.   
        /// </summary>   
        /// <param name="logManager">   
        /// The log manager.   
        /// </param>   
        public GoogleService(ILogManager logManager)   
        {   
            _logManager = logManager;   
        }   
   
        /// <summary>   
        /// The login async.   
        /// </summary>   
        /// <returns>   
        /// The <see cref="Task"/> object.   
        /// </returns>   
        public async Task<Session> LoginAsync()   
        {   
            var googleUrl = "https://accounts.google.com/o/oauth2/auth?client_id=" + Uri.EscapeDataString(Constants.GoogleClientId) + "&redirect_uri=" + Uri.EscapeDataString(Constants.GoogleCallbackUrl) + "&response_type=code&scope=" + Uri.EscapeDataString("https://www.googleapis.com/auth/userinfo.profile");   
            var startUri = new Uri(googleUrl);   
            var endUri = new Uri("https://accounts.google.com/o/oauth2/approval?");   
  
#if !WINDOWS_PHONE_APP   
           var webAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.UseTitle, startUri, endUri);   
           return await GetSession(webAuthenticationResult);   
#else   
            WebAuthenticationBroker.AuthenticateAndContinue(startUri, endUri, null, WebAuthenticationOptions.None);   
            return null;   
#endif   
        }   
           
        private string GetCode(string webAuthResultResponseData)   
        {   
            //Success code=4/izytpEU6PjuO5KKPNWSB4LK3FU1c   
            var index = webAuthResultResponseData.IndexOf("=", StringComparison.Ordinal);   
            return webAuthResultResponseData.Substring(index + 1);   
        }   
   
        /// <summary>   
        /// The logout.   
        /// </summary>   
        public void Logout()   
        {   
        }   
  
#if WINDOWS_PHONE_APP   
        public async Task<Session> Finalize(WebAuthenticationBrokerContinuationEventArgs args)   
        {   
            Exception exception = null;   
            try   
            {   
                return await GetSession(args.WebAuthenticationResult);   
            }   
            catch (Exception e)   
            {   
                exception = e;   
            }   
   
            await _logManager.LogAsync(exception);   
   
            return null;   
        }   
#endif   
        private async Task<Session> GetSession(WebAuthenticationResult result)   
        {   
            if (result.ResponseStatus == WebAuthenticationStatus.Success)   
            {   
                var code = GetCode(result.ResponseData);   
                var serviceRequest = await GetToken(code);   
   
                return new Session   
                {   
                    AccessToken = serviceRequest.access_token,   
                    ExpireDate = new DateTime(long.Parse(serviceRequest.expires_in)),   
                    Id = serviceRequest.id_token,   
                    Provider = Constants.GoogleProvider   
                };   
            }   
            if (result.ResponseStatus == WebAuthenticationStatus.ErrorHttp)   
            {   
                throw new Exception("Error http");   
            }   
            if (result.ResponseStatus == WebAuthenticationStatus.UserCancel)   
            {   
                throw new Exception("User Canceled.");   
            }   
            return null;   
        }   
   
        private static async Task<ServiceResponse> GetToken(string code)   
        {   
            const string TokenUrl = "https://accounts.google.com/o/oauth2/token";   
            var body = "code=" + Uri.EscapeDataString(code) + "&client_id=" + Uri.EscapeDataString(Constants.GoogleClientId) +   
                       "&client_secret=" + Uri.EscapeDataString(Constants.GoogleClientSecret) +   
                       "&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code";   
   
            var client = new HttpClient();   
            var request = new HttpRequestMessage(HttpMethod.Post, new Uri(TokenUrl))   
            {   
                Content = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded")   
            };   
            var response = await client.SendAsync(request);   
            var content = await response.Content.ReadAsStringAsync();   
            
            var serviceTequest = JsonConvert.DeserializeObject<ServiceResponse>(content);   
            return serviceTequest;   
        }   
    }

Here, we don´t have anything new, this is similar to the FacebookService.

Note: FacebookService and GoogleService are similar but the response and request are different for the reason that these classes are not joined.

The MicrosoftService

/// <summary>   
/// The microsoft service.   
/// </summary>   
public class MicrosoftService : IMicrosoftService   
{   
    private readonly ILogManager _logManager;   
    private LiveAuthClient _authClient;   
    private LiveConnectSession _liveSession;   
  
  
    /// <summary>   
    /// Defines the scopes the application needs.   
    /// </summary>   
    private List<string> _scopes;   
       
    /// <summary>   
    /// Initializes a new instance of the <see cref="MicrosoftService"/> class.   
    /// </summary>   
    /// <param name="logManager">   
    /// The log manager.   
    /// </param>   
    public MicrosoftService(ILogManager logManager)   
    {   
        _scopes = new List<string> { "wl.signin", "wl.basic", "wl.offline_access" };   
        _logManager = logManager;   
    }   
  
    /// <summary>   
    /// The login async.   
    /// </summary>   
    /// <returns>   
    /// The <see cref="Task"/> object.   
    /// </returns>   
    public async Task<Session> LoginAsync()   
    {   
  
        Exception exception = null;   
        try   
        {   
            _authClient = new LiveAuthClient();   
            var loginResult = await _authClient.InitializeAsync(_scopes);   
            var result = await _authClient.LoginAsync(_scopes);   
            if (result.Status == LiveConnectSessionStatus.Connected)   
            {   
                _liveSession = loginResult.Session;   
                var session = new Session   
                {   
                    AccessToken = result.Session.AccessToken,   
                    Provider = Constants.MicrosoftProvider,   
                };   
  
                return session;   
            }   
  
        }   
        catch (LiveAuthException ex)   
        {   
            throw new InvalidOperationException("Login canceled.", ex);   
        }   
  
        catch (Exception e)   
        {   
            exception = e;   
        }   
         await _logManager.LogAsync(exception);   
  
        return null;   
    }   
  
    /// <summary>   
    /// The get user info.   
    /// </summary>   
    /// <returns>   
    /// The <see cref="Task"/> object.   
    /// </returns>   
    public async Task<IDictionary<string, object>> GetUserInfo()   
    {   
  
        Exception exception = null;   
        try   
        {      
            var liveClient = new LiveConnectClient(_liveSession);   
            LiveOperationResult operationResult = await liveClient.GetAsync("me");   
  
            return operationResult.Result;   
        }   
        catch (LiveConnectException e)   
        {   
            exception = e;   
        }   
        await _logManager.LogAsync(exception);   
  
        return null;   
    }   
  
    /// <summary>   
    /// The logout.   
    /// </summary>   
    public async void Logout()   
    {   
  
        if (_authClient == null)   
        {   
            _authClient = new LiveAuthClient();   
            var loginResult = await _authClient.InitializeAsync(_scopes);   
        }   
        if (_authClient.CanLogout)   
        {   
            _authClient.Logout();   
        }   
    }   
}

This class was reused from the sample Authentication using Facebook, Google and Microsoft account in WP8.0 App (MVVM), but for it work is required to associate the app to the store.

That will result in an additional file in the project: as in the following:

Note

 

  1. These file are removed from the sample because each developer has their own.
  2. In devices that the Microsoft account is logged the application will do the login automatically.

The SessionService

/// <summary>   
/// The service session.   
/// </summary>   
public class SessionService : ISessionService   
{   
    private readonly IApplicationDataService _applicationSettings;   
    private readonly IFacebookService _facebookService;   
    private readonly IMicrosoftService _microsoftService;   
    private readonly IGoogleService _googleService;   
    private readonly ILogManager _logManager;   
       
    /// <summary>   
    /// Initializes a new instance of the <see cref="SessionService" /> class.   
    /// </summary>   
    /// <param name="applicationSettings">The application settings.</param>   
    /// <param name="facebookService">The facebook service.</param>   
    /// <param name="microsoftService">The microsoft service.</param>   
    /// <param name="googleService">The google service.</param>   
    /// <param name="logManager">The log manager.</param>   
    public SessionService(IApplicationDataService applicationSettings,   
        IFacebookService facebookService,   
        IMicrosoftService microsoftService,   
        IGoogleService googleService, ILogManager logManager)   
    {   
        _applicationSettings = applicationSettings;   
        _facebookService = facebookService;   
        _microsoftService = microsoftService;   
        _googleService = googleService;   
        _logManager = logManager;   
    }   
  
    /// <summary>   
    /// Gets the session.   
    /// </summary>   
    /// <returns>The session object.</returns>   
    public Session GetSession()   
    {   
        var expiryValue = DateTime.MinValue;   
        string expiryTicks = LoadEncryptedSettingValue("session_expiredate");   
        if (!string.IsNullOrWhiteSpace(expiryTicks))   
        {   
            long expiryTicksValue;   
            if (long.TryParse(expiryTicks, out expiryTicksValue))   
            {   
                expiryValue = new DateTime(expiryTicksValue);   
            }   
        }   
  
        var session = new Session   
        {   
            AccessToken = LoadEncryptedSettingValue("session_token"),   
            Id = LoadEncryptedSettingValue("session_id"),   
            ExpireDate = expiryValue,   
            Provider = LoadEncryptedSettingValue("session_provider")   
        };   
        _applicationSettings.LocalSettings[Constants.LoginToken] = true;   
        return session;   
    }   
  
    /// <summary>   
    /// The save session.   
    /// </summary>   
    /// <param name="session">   
    /// The session.   
    /// </param>   
    private void Save(Session session)   
    {   
        SaveEncryptedSettingValue("session_token", session.AccessToken);   
        SaveEncryptedSettingValue("session_id", session.Id);   
        SaveEncryptedSettingValue("session_expiredate", session.ExpireDate.Ticks.ToString(CultureInfo.InvariantCulture));   
        SaveEncryptedSettingValue("session_provider", session.Provider);   
        _applicationSettings.LocalSettings[Constants.LoginToken] = true;   
    }   
  
    /// <summary>   
    /// The clean session.   
    /// </summary>   
    private void CleanSession()   
    {   
        _applicationSettings.LocalSettings.Remove("session_token");   
        _applicationSettings.LocalSettings.Remove("session_id");   
        _applicationSettings.LocalSettings.Remove("session_expiredate");   
        _applicationSettings.LocalSettings.Remove("session_provider");   
        _applicationSettings.LocalSettings.Remove(Constants.LoginToken);   
    }   
  
    /// <summary>   
    /// The login async.   
    /// </summary>   
    /// <param name="provider">   
    /// The provider.   
    /// </param>   
    /// <returns>   
    /// The <see cref="Task"/> object.   
    /// </returns>   
    public async Task<bool?> LoginAsync(string provider)   
    {   
        Provider = provider;   
        Exception exception;   
        try   
        {   
            Session session = null;   
            switch (provider)   
            {   
                case Constants.FacebookProvider:   
                    session = await _facebookService.LoginAsync();   
                    break;   
                case Constants.MicrosoftProvider:   
                    session = await _microsoftService.LoginAsync();   
                    break;   
                case Constants.GoogleProvider:   
                    session = await _googleService.LoginAsync();   
                    break;   
            }   
            if (session == null)   
            {   
                return null;   
            }   
            Save(session);   
               
            return true;   
        }   
        catch (Exception ex)   
        {   
            exception = ex;   
        }   
        await _logManager.LogAsync(exception);   
  
        return false;   
    }   
  
    /// <summary>   
    /// Gets or sets the provider.   
    /// </summary>   
    /// <value>   
    /// The provider.   
    /// </value>   
    public string Provider { get; set; }   
  
    /// <summary>   
    /// The logout.   
    /// </summary>   
    public async void Logout()   
    {   
        Exception exception = null;   
        try   
        {   
            var session = GetSession();   
            switch (session.Provider)   
            {   
                case Constants.FacebookProvider:   
                    _facebookService.Logout();   
                    break;   
                case Constants.MicrosoftProvider:   
                    _microsoftService.Logout();   
                    break;   
                case Constants.GoogleProvider:   
                    _googleService.Logout();   
                    break;   
            }   
            CleanSession();   
        }   
        catch (Exception ex)   
        {   
            exception = ex;   
        }   
        if (exception != null)   
        {   
            await _logManager.LogAsync(exception);   
        }   
    }   
  
WINDOWS_PHONE_APP   
    public async Task<bool> Finalize(WebAuthenticationBrokerContinuationEventArgs args)   
    {   
        Exception exception = null;   
        try   
        {   
            Session session = null;   
            switch (Provider)   
            {   
                case Constants.FacebookProvider:   
                    session = await _facebookService.Finalize(args);   
                    break;   
                case Constants.GoogleProvider:   
                    session = await _googleService.Finalize(args);   
                    break;   
            }   
            Save(session);   
            return true;   
        }   
        catch (Exception e)   
        {   
            exception = e;   
        }   
        await _logManager.LogAsync(exception);   
        return false;   
    }   
if   
    /// <summary>   
    /// Loads an encrypted setting value for a given key.   
    /// </summary>   
    /// <param name="key">   
    /// The key to load.   
    /// </param>   
    /// <returns>   
    /// The value of the key.   
    /// </returns>   
    private string LoadEncryptedSettingValue(string key)   
    {   
        string value = null;   
  
        var protectedBytes = _applicationSettings.LocalSettings[key];   
        if (protectedBytes != null)   
        {   
            // todo use DataProtectionProvider   
            // byte[] valueBytes = ProtectedData.Unprotect(protectedBytes, null);   
            // value = Encoding.UTF8.GetString(valueBytes, 0, valueBytes.Length);   
            value = protectedBytes.ToString();   
        }   
  
        return value;   
    }   
  
    /// <summary>   
    /// Saves a setting value against a given key, encrypted.   
    /// </summary>   
    /// <param name="key">   
    /// The key to save against.   
    /// </param>   
    /// <param name="value">   
    /// The value to save against.   
    /// </param>   
    /// <exception cref="System.ArgumentOutOfRangeException">   
    /// The key or value provided is unexpected.   
    /// </exception>   
    private void SaveEncryptedSettingValue(string key, string value)   
    {   
        if (!string.IsNullOrWhiteSpace(key) && !string.IsNullOrWhiteSpace(value))   
        {   
            // todo use DataProtectionProvider   
            // byte[] valueBytes = Encoding.UTF8.GetBytes(value);   
            // var dataProtectionProvider = new DataProtectionProvider();             
            // // Encrypt the value by using the Protect() method.   
            // byte[] protectedBytes = await dataProtectionProvider.ProtectAsync(valueBytes);   
            _applicationSettings.LocalSettings[key] = value;   
        }   
    }   
}

This class will return null if the session is null, we need to be aware that there isn´t any error and the session is returned or if it is null, the process will be done by the Finalize method.

Here is the class diagram with all classes and interfaces created in this sample:

Now to build the User Interface and because we are using the MVVM pattern, it created a LoginViewModel to do the binding to the LoginView.

The LoginViewModel

/// <summary>   
    /// The login view model.   
    /// </summary>   
    public class LoginViewModel : ViewModelBase   
    {   
        private readonly ILogManager _logManager;   
        private readonly IMessageBoxService _messageBox;   
        private readonly INetworkInformationService _networkInformationService;   
        private readonly INavigationService _navigationService;   
        private readonly ISessionService _sessionService;   
        private bool _inProgress;   
   
        /// <summary>   
        /// Initializes a new instance of the <see cref="LoginViewModel"/> class.   
        /// </summary>   
        /// <param name="navigationService">   
        /// The navigation service.   
        /// </param>   
        /// <param name="sessionService">   
        /// The session service.   
        /// </param>   
        /// <param name="messageBox">   
        /// The message box.   
        /// </param>   
        /// <param name="networkInformationService">   
        /// The network connection.   
        /// </param>   
        /// <param name="logManager">   
        /// The log manager.   
        /// </param>   
        public LoginViewModel(INavigationService navigationService,   
            ISessionService sessionService,   
            IMessageBoxService messageBox,   
            INetworkInformationService networkInformationService,   
            ILogManager logManager)   
        {   
            _navigationService = navigationService;   
            _sessionService = sessionService;   
            _messageBox = messageBox;   
            _networkInformationService = networkInformationService;   
   
            _logManager = logManager;   
            LoginCommand = new RelayCommand<string>(LoginAction);   
        }   
   
        /// <summary>   
        /// Gets the navigation service.   
        /// </summary>   
        /// <value>   
        /// The navigation service.   
        /// </value>   
        public INavigationService NavigationService   
        {   
            get { return _navigationService; }   
        }   
   
        /// <summary>   
        /// Gets or sets a value indicating whether in progress.   
        /// </summary>   
        /// <value>   
        /// The in progress.   
        /// </value>   
        public bool InProgress   
        {   
            get { return _inProgress; }   
            set { Set(() => InProgress, ref _inProgress, value); }   
        }   
   
        /// <summary>   
        /// Gets the facebook login command.   
        /// </summary>   
        /// <value>   
        /// The facebook login command.   
        /// </value>   
        public ICommand LoginCommand { get; private set; }   
   
        /// <summary>   
        /// Facebook's login action.   
        /// </summary>   
        /// <param name="provider">   
        /// The provider.   
        /// </param>   
        private async void LoginAction(string provider)   
        {   
            Exception exception = null;   
            bool isToShowMessage = false;   
            try   
            {   
                if (!_networkInformationService.IsNetworkAvailable)   
                {   
                    await _messageBox.ShowAsync("There isn´t network connection.",   
                                          "Authentication Sample",   
                                          new List<string> { "Ok" });   
                    return;   
                }   
                if (Constants.GoogleClientId.Contains("<") || Constants.GoogleClientSecret.Contains("<"))   
                {   
                    await _messageBox.ShowAsync("Is missing the google client id and client secret. Search for Constant.cs file.",   
                                         "Authentication Sample",   
                                         new List<string> { "Ok" });   
                    return;   
                }   
                if (Constants.FacebookAppId.Contains("<"))   
                {   
                    await _messageBox.ShowAsync("Is missing the facebook client id. Search for Constant.cs file.",   
                                         "Authentication Sample",   
                                         new List<string> { "Ok" });   
                    return;   
                }   
                InProgress = true;   
                var auth = await _sessionService.LoginAsync(provider);   
                if (auth == null)   
                {   
                    return;   
                }   
                if (!auth.Value)   
                {   
                    await ShowMessage();   
                }   
                else   
                {   
                    _navigationService.Navigate<MainView>();   
                    InProgress = false;   
                }   
   
                InProgress = false;   
            }   
            catch (Exception ex)   
            {   
                InProgress = false;   
                exception = ex;   
                isToShowMessage = true;   
            }   
            if (isToShowMessage)   
            {   
                await _messageBox.ShowAsync("Application fails.",   
                                           "Authentication Sample",    
                                            new List<string> { "Ok" });   
            }   
            if (exception != null)   
            {   
                await _logManager.LogAsync(exception);   
            }   
        }   
   
        private async Task ShowMessage()   
        {   
            await _messageBox.ShowAsync("Wasn´t possible to complete the login.",   
               "Authentication Sample",   
                new List<string>   
                {   
                   "Ok"    
                });   
        }   
  
#if WINDOWS_PHONE_APP   
        public async void Finalize(WebAuthenticationBrokerContinuationEventArgs args)   
        {   
            var result = await _sessionService.Finalize(args);   
            if (!result)   
            {   
                await ShowMessage();   
            }   
            else   
            {   
                _navigationService.Navigate<MainView>();   
                InProgress = false;   
            }   
        }   
#endif   
    }

Note: In the LoginAction the parameter provider is the value of the CommandParameter received in LoginCommand, this is set in the login page.

For the final the code, let’s see the code for the page.

The LoginPage.xaml

<Page   
    x:Class="AuthenticationSample.UniversalApps.Views.LoginView"   
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"   
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"   
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"   
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"   
    xmlns:converters="using:Cimbalino.Toolkit.Converters"   
    mc:Ignorable="d">   
   
    <Page.DataContext>   
        <Binding Mode="OneWay"   
                 Path="LoginViewModel"   
                 Source="{StaticResource Locator}" />   
    </Page.DataContext>   
    <Page.Resources>   
        <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>   
    </Page.Resources>   
    <!--  LayoutRoot is the root grid where all page content is placed  -->   
    <Grid x:Name="LayoutRoot" Background="LightGray">   
        <Grid.RowDefinitions>   
            <RowDefinition Height="{StaticResource HeaderHeigth}" />   
            <RowDefinition Height="*" />   
        </Grid.RowDefinitions>   
   
        <!--  TitlePanel contains the name of the application and page title  -->   
        <StackPanel x:Name="TitlePanel"    
                    Margin="{StaticResource HeaderMargin}"   
                    VerticalAlignment="Center" Grid.Row="0">   
            <TextBlock  FontSize="30"    
                        Foreground="Black"   
                       Text="Login"/>   
        </StackPanel>   
   
        <!--  ContentPanel - place additional content here  -->   
        <Grid x:Name="ContentPanel"   
              VerticalAlignment="Center"   
              HorizontalAlignment="Center"   
              Grid.Row="1">   
            <Grid.RowDefinitions>   
                <RowDefinition Height="Auto" />   
                <RowDefinition Height="80" />   
                <RowDefinition Height="80" />   
                <RowDefinition Height="80" />   
                <RowDefinition Height="80" />   
            </Grid.RowDefinitions>   
            <TextBlock Grid.Row="0"    
                       FontSize="20"   
                       Foreground="Black"   
                       Text="Use your account"/>   
            <Button Grid.Row="1" Width="300"   
                    Margin="10"   
                    Command="{Binding LoginCommand}"   
                    CommandParameter="facebook"   
                    Background="{StaticResource FacebookBlueBackgroundBrush}" >   
                <StackPanel Orientation="Horizontal">   
                    <TextBlock Text="ï‚š"    
                                   VerticalAlignment="Center"   
                                   FontFamily="/Fonts/fontawesome-webfont.ttf#FontAwesome"    
                                   HorizontalAlignment="Left"/>   
                    <TextBlock Margin="10,0,0,0" Text="Facebook"    
                           HorizontalAlignment="Center"/>   
                </StackPanel>   
            </Button>   
            <Button Grid.Row="3"   
                    Margin="10" Width="300"   
                    Command="{Binding LoginCommand}"   
                    CommandParameter="microsoft"   
                    Background="{StaticResource MicrosoftBlueBackgroundBrush}" >   
                <StackPanel Orientation="Horizontal">   
                    <TextBlock Text="ï…º"   
                                   VerticalAlignment="Center"   
                                   FontFamily="/Fonts/fontawesome-webfont.ttf#FontAwesome"    
                                   HorizontalAlignment="Left"/>   
                    <TextBlock Margin="10,0,0,0" Text="Microsoft"    
                           HorizontalAlignment="Center"/>   
                </StackPanel>   
            </Button>   
            <Button Grid.Row="2" Width="300"   
                    Margin="10"   
                    Command="{Binding LoginCommand}"   
                    CommandParameter="google"   
                    Background="{StaticResource GoogleRedBackgroundBrush}" >   
                <StackPanel Orientation="Horizontal">   
                    <TextBlock Text=""   
                                   VerticalAlignment="Center"   
                                   FontFamily="/Fonts/fontawesome-webfont.ttf#FontAwesome"    
                                   HorizontalAlignment="Left"/>   
                    <TextBlock Margin="10,0,0,0" Text="Google"    
                           HorizontalAlignment="Center"/>   
                </StackPanel>   
            </Button>   
        </Grid>   
        <Grid Visibility="{Binding InProgress, Converter={StaticResource BooleanToVisibilityConverter}}"   
            Grid.Row="0"   
                   Grid.RowSpan="2">   
            <Rectangle    
                   Fill="Black"   
                   Opacity="0.75" />   
            <TextBlock    
                   HorizontalAlignment="Center"   
                   VerticalAlignment="Center"   
                   Text="Auth..." />   
            <ProgressBar IsIndeterminate="True" IsEnabled="True" Margin="0,60,0,0"/>   
        </Grid>   
   
    </Grid>   
</Page>

For use in the same page in Windows 8.1 Store apps and Windows Phone 8.1 Runtime was used some style.

The LoginView.xaml.cs

/// <summary>   
    /// An empty page that can be used on its own or navigated to within a Frame.   
    /// </summary>   
#if WINDOWS_PHONE_APP   
       public sealed partial class LoginView : Page, IWebAuthenticationContinuable   
#else   
      public sealed partial class LoginView : Page   
#endif   
    {   
        /// <summary>   
        /// Initializes a new instance of the <see cref="LoginView"/> class.   
        /// </summary>   
        public LoginView()   
        {   
            InitializeComponent();   
        }   
   
        /// <summary>   
        /// The on navigated to.   
        /// </summary>   
        /// <param name="e">   
        /// The e.   
        /// </param>   
        protected override void OnNavigatedTo(NavigationEventArgs e)   
        {   
            var viewModel = (LoginViewModel)DataContext;   
            viewModel.NavigationService.RemoveBackEntry();   
            base.OnNavigatedTo(e);   
        }   
  
#if WINDOWS_PHONE_APP   
   
        /// <summary>   
        /// Continues the web authentication.   
        /// </summary>   
        /// <param name="args">The <see cref="Windows.ApplicationModel.Activation.WebAuthenticationBrokerContinuationEventArgs"/> instance containing the event data.</param>   
        public void ContinueWebAuthentication(Windows.ApplicationModel.Activation.WebAuthenticationBrokerContinuationEventArgs args)   
        {   
            var viewModel = (LoginViewModel)DataContext;   
            viewModel.Finalize(args);   
        }   
#endif   
    }

Conclusion

In conclusion, the flow is completely different for each platform and it has some impact in the development and in sharing the code. Maybe, for this reason there isn’t any package for Windows Phone 8.1 that uses authentication.

Source Code

The source code can be found here.

Source Code Files

  • IFacebookService interface for FacebookService
  • IGoogleService interface for GoogleService
  • ILogManager interface for LogManager
  • IMicrosoftService interface for MicrosoftService
  • ISessionProvider interface for all providers interface (common methods)
  • ISessionService for SessionService
  • Session class for save the information about the session (provider, token, expired date)
  • FacebookService class that has all logic about the login / logout using Facebook provider
  • GoogleService class that has all logic about the login / logout using Google provider
  • MicrosoftService class that has all logic about the login / logout using Microsoft provider
  • SessionService class for manage login/logout (it will use all services provides described before)
  • LoginViewModel class for binding to LoginView.xaml
  • LoginView class that represent the page for login
  • MainViewModel class for binding to MainView.xaml
  • MainView class that appear after the login is ok
  • ViewModelLocator class contains static references to all the view model in application and provides an entry point for the bindings.

The solution

Build the Sample

  1. Start Visual Studio Express 2012 for Windows 8 and select File > Open > Project/Solution.
  2. Go to the directory in which you unzipped the sample. Go to the directory named for the sample and double-click the Visual Studio Express 2012 for Windows 8 Solution (.sln) file.
  3. Press F7 or use Build > Build Solution to build the sample.

Note: you can use Visual Studio 2013 in Windows 8.1.

Run the sample

To debug the app and then run it, press F5 or use Debug > Start Debugging. To run the app without debugging, press Ctrl+F5 or use Debug > Start Without Debugging

Output

The output for each target is:

  • Windows 8.1 Store App

Login Page

Microsoft Authentication

Facebook Authentication

Google Authentication

  • Windows Phone 8.1 App

Login View

Facebook Authentication

Google Authentication

 

Interview with a Visual C# MVP Wiki Ninja – Sara Silva

Today was published my interview for Wiki Ninjas blog.

” Wiki Ninjas is a group of authors who celebrate and evangelize the community catalyst and social-authoring excellence that is called TechNet Wiki “

wiki ninjas

The full interview is here:

Interview with a Visual C# MVP Wiki Ninja – Sara Silva

My first experience about my new Nokia X

In the last week I received a Nokia X device, I know that the news about it are not goods, Microsoft kills off its Nokia Android phones, but it did not died, yet.

Normally I use Nokia Lumia 925 and 920 with Windows Phone 8.1 Dev Preview and the first moments with Nokia X was to do the same I usually do when I do a hard reset or work with a new device. The first thing I do is to set my Microsoft account for upload all my contacts, but I did not find a way to do this in Nokia X and was sad for me! Another thing was taken screenshots, I use this feature a lot, and in Nokia X is possible to take screenshots pressing Volum Down + Power button, really nice.

About the contacts I can do the basic operation and I can import/export contacts or connect to my accounts, but not find a way to connect Microsoft account, like I do in WP.
contacts

Here is a sample the accounts I connected
connected contacts

The information about my device is here

about phone

Is not the Nokia X2, but is nice for explore it.

 

The action center is similar to Windows Phone, but in Windows Phone I have more information and options that is very useful to quicky definitions.

action center

Nokia X allow to have a track about all operation in my device, interesting in some case like a download made from website and I did not where was saved.

recent

The lock screen is complete different from Windows Phone and I is updated constantly, for example I have some e-mail that I marked as unread and sometime the device tells me you have emails to read, even I visit the email app and quit. I did not liked it :)

notifications

 

Another thing I was strange for me, is related with email accounts. I setted two different emails accounts and would like to have two icons for it, but I only have one and in email I need to select each email account want to see, and the notification about the number the emails to read is relative to the email account selected… I prefer the Windows Phone way! :)

In this moment, I am using apps like facebook, twitter, skype, email, …and it has a similar experiencie as in Windows Phone.

In future, I want to try more apps and I want to see how easy is to port apps from Android to Nokia X and deploy from Xamarin.

Note: I installed an Android app that is in development and was easy, I installed only the apk! I did not need any developer account like in Windows Phone, was nice.

 

[TechNet Wiki] Windows Phone and Windows Store Apps Technical Guru – June 2014

Yesterday was published the The Microsoft TechNet Guru Awards! (June 2014) from TechNet Wiki and for the second consecutive month I won the

Windows Phone and Windows Store Apps Technical Guru - June 2014 

Technical Guru

 

I am really happy! :)

You can read my article here:

Creating Windows Phone and Window 8.1 applications using Microsoft App Studio

 

DataTable Design View for Azure SQL Database

This article has the goal to show a way to explore an Azure SQL Database, in especial the datatable design view.

Microsoft SQL Server Management Studio   is a great tool for management our databases, but for how is using Azure SQL Database there is an “issue” we find in the first time we try to explorer the database. When we try to see a table in design mode we cannot do it, only is possible to use SQL script, what can be a slow process for how don´t have so much experience with SQL.

Visual Studio 2013 allow to explore SQL database and has feature for show de design view.

Let’s see how it works for show an Azure SQL Database.

First in Server explorer, we need to connect to Azure account and then selecting the SQL Database we should click in “Open SQL Server Object Explorer” like we can see in the follow image:

open explorar

After this, will be show a popup to connect to the database (you maybe need to set your IP in Azure Firewall)

login

Now we are connected to the Azure SQL Database:

connected

In this sample is used a free database with two scheme (dbo and testforblob).

Now we are available to see the data and see the table in design view, for it we should use the context menu:

open design

The result of “View Designer” is:

design

In this view we can edit the table definition using design view.

And the result of “View Data” is

data

In this view we can change the data about orders that is a quickly way for it, without SQL.

In conclusion, Visual Studio 2013 has a great mode to explorer database and allow to have design view for Azure SQL Database what is very useful for management databases. And the other great thing is I not need to have Microsoft SQL Server Management Studio  installed in our machine (at least for simple and basic task!)

Comunidade Portuguesa de SharePoint, 34ª reunião presencial dia 12/07/2014!

 sps

Caros SharePointianos,  no próximo Sábado dia 12/07/2014 , irá ter lugar a 34ª Reunião da Comunidade
Portuguesa de SharePoint.
É muito importante a presença de todos, e como é habitual , as reuniões da Comunidade irão decorrer presencialmente.

Atenção,  esta reunião realizar-se-á nas novas  instalações da Microsoft na Expo.

Assim, este Sábado iremos assistir às seguintes sessões:
SESSÂO DEV01
Integrating Office 365 with Xamarin apps
image010
Nesta sessão, a Sara Silva irá apresentar uma solução de integração do Office 365 com aplicações Xamarin tendo como principal objectivo o de maximizar o código partilhado.

 

Eu Sara Silva, Novabase

Bio-Sketch: Microsoft MVP – Visual C#, Nokia Developer Champion, licenciada em Matemática – Especialidade em Computação, pela Universidade de Coimbra, e  é Microsoft Certified Profissional Developer.

Atualmente o seu foco de desenvolvimento incide em Windows Phone, Windows 8 Store Apps, Xamarin e Azure.
O seu blog é www.saramgsilva.com e o twitter é @saramgsilva.

.

SESSÂO DEV02
Beginning SharePoint Development
image010
SharePoint is a huge Microsoft platform that is been evolving since 2001.
So “im a  newbie in SharePoint what’s out there for me ? Where and how can i start?”
In this session learn what do you have to know to start your SharePoint development, environments, drawbacks, tools, and hard sweated lessons from an developer that refuses to retired

.

me Rodrigo Pinto, everis

Bio-Sketch: With 15 years of experience in Software Engineering & Architecture, Rodrigo Pinto is a Solution Architect, SharePoint MVP, Specialist & Evangelist at Everis.
Responsible for the SharePoint area tends to use innovation in creating new solutions and development strategies.
Speaker since 2009 , is delivering regular sessions in Microsoft Events: Techdays, RoadtoSharePoint, Lightup SharePoint, Microsoft RoadShow, SharePoint Connections, European SharePoint Conference,User Group Meetings and online events.

 

He Started the SharePoint Portuguese User Group and loves the idea By and For the Community.

.

É um membro activo da Comunidade Portuguesa de SharePoint

image010

image010

Agenda

09:30: Recepção dos participantes

10:00: Abertura

10:05: Sessão: “Integrating Office 365 with Xamarin apps” com Sara SilvaNovabase

11:05: Coffee-break

11:20: Sessão: “Beginning SharePoint Development” com Rodrigo Pintoeveris

12:20: Painel de discussão

13:00: Final da Reunião & Lunch

( Almoço em grupo para convívio. A participação no almoço é opcional.)

Aquele abraço, com muitos disposes à mistura !
Rodrigo Pinto, SharePoint MVP, Specialist, Evangelist
SharePointPt Founder
SharePointPT- Comunidade Portuguesa de SharePoint
SharePointPt Site: http://www.sharepointpt.org
SharePointPt no FaceBook: http://www.facebook.com/profile.php?id=100000660657466&ref=mf
SharePointPt no Twitter: http://twitter.com/spugpt
SharePointPt Email Account : spugpt@gmail.com;

image010

Como chegar:

 O local do evento é no Auditório da Microsoft na Expo (perto do Oceanário)

 Morada:

MSFT, Software para Microcomputadores, Lda.
(Subsidiária da Microsoft Corporation)
Rua do Fogo de Santelmo, Lote 2.07.02
1990 – 110 Lisboa

Microsoft Game Dev Camp – Lisboa

Microsoft Game Dev Camp | Lisboa

Microsoft Game Dev Camp | Lisboa
Event ID: 1032590886

Microsoft Lisbon Experience

Rua do Fogo de Santelmo, Lote 2.07.02
Lisboa Lisboa 1990 – 110
Portugal
Register by Email: gamedevpt@microsoft.com
Language(s): English.
Product(s): Microsoft Visual Studio, Windows, Windows Azure, Windows Phone and Xbox.
Audience(s): Academic, Additional Information Worker, Designer, Developer Generalist, Marketing – Partners, NonProfessional Developer, Pro Dev/Programmer, Project Manager, Tech Influencing BDM, Tech Support – Partners and Tester.

You probably dream all day of creating the next big game. Not the next Angry | Flappy thing, but *your* game. Your idea. The one that will get everyone to talk about it on the bus, on the beach, and will drive parents and bosses nuts all around the world. The one that will have video walkthroughs done by guys 1,000kms from you, and competitions of prizes that you only see in magazines. You’re probably already on your way to make it. Or you’re starting. And on your spare time of dreaming and building that dream, you visit those amazing conference sites for Game Creators like GDC, DEVELOP, and others – on your web browser, because you can’t (yet) make the trip. Or, heck, you just build games because you love them.

We want to help you create that game – and take the next step with the ones you’re already building. Right here inPortugal

That’s why we created the first GAME DEV CAMP on the next 18th of Julytogether with some of the *hottest* names of the game developer industry, both from our country and Europe. The big event will bring together 300+ attendees who, like you, are quite literally living the dream of creating awesome games – and with 25+ sessions divided in 5 Tracks to help you choose between topics like Dev, Game Design, Visual Arts, Marketing&Management and a special track of sessions called “INSPIRE”, the hardest thing will be picking which ones to attend! We will bring you some of the best examples of games “made in Portugal” and their stories, but also a sneak peek into some of the new developments in the industry ;-)

See you in Lisbon!

The Microsoft Developer Experience & Evangelism Team

—————————————————————————————————

>>REGISTRATION<<

The registration for Microsoft Game Dev Camp is free (or, as we say in Portuguese, “à borlix”) and, until the 30th of June is open *EXCLUSIVELY* to all the community of game developers – and especially the ones who are building games “made in Portugal”! So, do you have a game, a startup, a project or even an idea in development for a game and you feel part of this community? All you have to do to secure one of the seats available – 250 only! – is send an e-mail with your registration data for you and every member of your team (if applicable), to GAMEDEVPT@MICROSOFT.COM.What do you need to send for each? Name, address, email, telephone and game – URL, idea description, you choose! – or, in alternative, tell us in a sentence why you deserve to be at the event) ;-)

Then you’ll receive a confirmation e-mail that you can use to brag to everyone you know – with our support!

OPEN REGISTRATION: we’ll also have some special dates where you’ll be able to guarantee your spot, if you’re not able to secure one with the requirements above! On the 1st of July between 09h00 and 19h00 (today!) we’ll make 100* seatsavailable for open registration right here on the site (on that right menu, where it says “Register” - *now open!*)! And more to come, depending on the seats still available ;-)

*first-come-first-served, and we’ll close registration when the maximum capacity is achieved!

Note: there will be a *free bus service* serving the trip Porto-Lisbon-Porto and limited seats will be managed in partnership with Nerdmonkeys and PressPlay. For more info on this special transport send an e-mail to gamedevpt@microsoft.com with the title “GameDevBus: registration request” and we’ll get you in touch with the team that is organizing the trip! ;-)

—————————————————————————————————

 


>>AGENDA<<

Together with our friends from GameSparks, BioDroid, Gameover.Sapo.PT, Bica Studios and Nerdmonkeys, we’re polishing up the final agenda for the Game Dev Camp, which we will announce on the 1st  week of July :-)

But we’ll be launching a good set of teasers until then right here on the registration page. The best part is that these sessions will be led by some of the biggest experts on the topics both in our country (and responsible for some of the most amazing games “made in Portugal”) and beyond. Stay tuned!

25 (1h) SESSIONS IN TOTAL. 1 MAIN KEYNOTE. 5 DIFFERENT TRACKS/ROOMS.

Source:
http://aka.ms/lxgamedevcamp

Creating Windows Phone and Window 8.1 applications using Microsoft App Studio

 

This article aims to present the Microsoft App Studio for creating applications for Windows Phone 8.1 and Windows 8.1.

A few months ago Microsoft released Windows Phone App Studio Beta, a service that allows any person without programming skills to can create applications for Windows Phone in just 4 steps: have an idea, add content, choose style and use the application. Recently, more specifically in the Microsoft //Build/ event, that took place last April, a new version of the service was released alongside the beta version of Windows App Studio, which in addition to the Windows Phone applications, allows the creation of Windows 8.1 applications.

The service can be accessed from appstudio.windowsphone.com. To start with this service, the user is required to have an Outlook.com account or, in case the user doesn’t have an account of these, any Microsoft Id will work. For accounts that not fits with theses, the email account can be associated with Microsoft Id, and for it the user should use the link http://bit.ly/1gywtmO or in login page, click in Sign up.

 

The first time we do the login, the website will show a screen for allow the App Studio to access our account, which can be changed later if we wish to. After this, we need to accept the terms of use and we need to define the user for the email account we are using.

At this moment, we are ready for start creating application! For it we only need to click the button “Start new project”.

 

App Studio provides a set of templates for help the users in creating application. Theses templates are application demos for a specific context which are more used.

 

 

Noteworthy is that all the templates are C # / XAML applications and are available for both Windows Phone 8.1 and Windows 8.1, except for the Web App Template which is only available for Windows Phone.

When selecting a template of type “Empty App” we are creating an application from scratch. This template is often used when the other templates do not meet the needs of the user or for more advanced users who already have some experience with App Studio.

The user will set all kinds of content, styles and will have to use all your creativity to build a “great app”. In the case of the “Web App Template” the user will also create the application from scratch, but in this case is given a base Url which will be the starting point of the application and have access to some buttons on “AppBar”, this template is ideal for website that suits to the mobile devices. On the other hand, other templates allow to have a quick guide
in the application we are building and we only have to change the data and customize the application.

 

Now, let’s see in practice how we create applications with these templates.

 

Contoso Ltd Template

After we select the template, a screen will be shown where we can have a first look at the app. This is a simple simulation the app for Windows Phone and Windows 8.1 that does not allow to navigate to the details pages.

 

This screen allows us to have an idea about the application without installing it. Let’s see the configuration for this template.

 

Content

The first page shows the application name and logo (left, at the top) and shows all definitions for the content of the app, which, in this case, has five sections:

  • About us is an HTML section
  • Catalogue is a dynamic collection section
  • Team is a dynamic collection section
  • News is a Bing section
  • Contact us is a menu section which has menu actions

There’s a limit of up to six sections. After each section is created we can edit, delete or move the section position with the goal to define the best order for it.

For each section we can select one of the following options:

  • RSS – A list of sets of information based on an RSS feed that you enter when creating the data source.
  • Html – A single page of static text that you enter.
  • Youtube – A list of videos with titles and descriptions based on a YouTube channel or search that you enter when creating the data source.
  • Flickr – A list of images and their corresponding data based on a Flickr UserId or search that you enter when creating the data source.
  • Bing – A list of news
  • Facebook – A Facebook feed from a public Facebook page.
  • Instagram – a Instragram feed based in a tag
  • Menu – allow to create menu action which can use other apps (for example: using an address for Here Maps, using a phone number for make a call phone, and others)
  • Collection – A list of items with columns of characteristics. The collection can be static or dynamic and if the collection is dynamic the data can be imported or exported for a CSV file.

A future feature will be the twitter feed, but at this moment this is not available in App Studio, but was mentioned in a //build/ session on this subject.

App Studio already has a comprehensive list of data sources, allowing the user to create compelling apps. However, these data sources are based on RSS feeds which have a limited number of items and some presentation limitations

Theme

In this page, we can define the background image or the background color, define the text color and the application bar color. There are three option: custom style (using a background image), dark style and a light style. The Select button allows to define the style and then we need to save the configuration.

 

Tile

 

In the Tiles tab, we can define tiles for the application and we can select one type from the three available types: Flip Template,
Cycle Template and Icon Template. In this case was selected the Cycle Template and the respective images.

In the Splash & Lock separator, we define the images for o splash screen and for lock screen, for both apps.

This page doesn’t mention the size of the images but when we try to upload it, will be shown the allowed size if our images don´t fit those values.

 

Publish


In this page, the language for the app is defined. For now it is only possible to select one. It is possible to define the title, the description, and we can define if the app has an About page or even ads (but it requires development in Visual Studio). Before the finalize step it is possible to associate the app with the store, which requires a reserved name in Store Dashboard.

After all configuration we are available to finalize the app by clicking in Finish button.

 

Finish


 

On this page you can view the applications for each target platform (not being able to navigate) and it is possible to generate the application to get the application packages for install on each device and then get the source code. Clicking on the “Generate” button we get a screen where we can choose which application we want to generate.

 

 

We can generate for both cases, which implies two different generations. However, for a more experienced user that uses Visual Studio to test our application, it is recommend the generation for Windows 8.1, because the generated code is an “universal app” solution that consists of the Windows Application project Phone 8.1, Windows 8.1 application for the project, shared between the previous projects and also contains a project of type “portable class library” with the whole data structure.

After this step, we can get the application packages that allow to test the application in our devices, or we ca get the source code and then test the application in simulator or in a device using Visual Studio (but for it is a requirement to have the developer account). Is possible to install the application package directly in the device using the QRCode provided and is possible to share, in social network, the url for the application.

When we generate the application for Windows 8.1 we get this screen

Where we can get the package for the Windows 8.1 application and then we can use PowerShell to install it in our PC with Windows 8.1.

 

And we can get the source code, which the solution is a Universal App, whit the following structure:

 

With the source code, each application can be extended in order to add new features such as:

  • Add more resource strings (localization)
  • Add ads configuration
  • Add Twitter feed
  • Change the user interface

amongst others …

 

Web App Template

Like it was mentioned, this template is only available for Windows Phone and this is a Web App. Let’s now see in practice how we can use this template.

When we select the Web App Template we will see this page

 

As we can see, the content of this app is only a reference for a url, which is a website that supports mobile devices.

For example, this template uses the m.microsoft.com url, but we can change it for use any another url, like: booking.com, m.sapo.pt, m.vodafone.pt, amongst other references…

The definition for Theme, Tile and Publish are the same as we saw in Contoso Ltd template.

When we click in the Finish button, we will get to a page for generating the application packages and the source code. And when we click in Generator we will see this screen

 

The final result of the application, using the reference m.sapo.pt is

 

The application from App Studio should be tested in different devices to ensure that the application works propertly and is like we defined. Only after completing the tests, the application must be submited to the store. Recall that in the Publish page we had the option to connect the application to the store, and on the final page after the generation of the application is provided in the reference to submit in store. The applications generated by App Studio will be pass in certification process like an application developed by a programmer.

For more advanced users, who wish to extend the application giving new functionality, they don´t have a way to submit the changes in the App Studio. The solution is to do a “merge” between the modified source code and the new version of the application. And starting the moment the source code is changed, the user is responsible for the creation of application packages using Visual Studio

For more information about this subject, see the curation Building apps without code using AppStudio that contains articles, videos and others resources about App Studio.

 

In conclusion, the App Studio presents a quick solution to develop applications for both Windows Phone and 8.1 for Windows, and we can extend the functionality of the application through the generated source code. I’d like to point out that, despite all the associated automation, there are some limitations that should be worked out in the future, so that applications generated by the App Studio will have more quality.