Cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Fitbit API for Windows Phone

I'm currently trying to develop a simple application for Windows Phone 8.1 using the Fitbit API where a user logs in with their Fitbit login details (using OAuth) and a simple page is then shown with some of their Fitbit information (such as height, weight etc).

 

I've looked at the Fitbit .NET Client Library from this link: https://github.com/aarondcoleman/Fitbit.NET

I can see it working as a Desktop application fine, but I've come to believe it doesn't work for Windows Phone 8.1.

 

There are many sources online that state the Fitbit API works for Windows Phone, so there must be a way to do this:

https://github.com/aarondcoleman/Fitbit.NET/issues/42

https://groups.google.com/forum/?pli=1#!topic/fitbit-api/Led89S3Z9iY
https://groups.google.com/forum/?pli=1#!topic/fitbit-api/Dcikk7DSusM
Example of a Windows Phone 8/8.1 app using the Fitbit API: http://www.windowsphone.com/en-us/store/app/fitbit-tracker/af1e2d65-5004-449b-a967-ac7c67c47493

 

Next, I looked into the Fitbit Web API, specifically at the OAuth Authentication for the Fitbit Web API from here: https://wiki.fitbit.com/display/API/OAuth+Authentication+in+the+Fitbit+API And I found some sample code for this authentication here: https://groups.google.com/forum/#!topic/fitbit-api/HjoDGXp5634However, there are many symbols which aren't recognised such as "OAuthService", "Context", "Response" and "Session".

 

Here's an example of the code I'm currently using, but I'm not sure if it's correct:

 

            const string ConsumerKey = "my-consumer-key-here";
            const string ConsumerSecret = "my-consumer-secret-here";

            // API call path to get temporary credentials (request token and secret)
            const string RequestTokenUrl = "https://api.fitbit.com/oauth/request_token";

            // Base path of URL where the user will authorize this application
            const string AuthorizationUrl = "https://www.fitbit.com/oauth/authorize";

            // API call path to get token credentials (access token and secret)
            const string AccessTokenUrl = "https://api.fitbit.com/oauth/access_token";

            // API call path to protected resource
            const string ApiCallUrl = "http://api.fitbit.com/1/user/-/activities/date/2011-01-25.xml";

            // Create OAuthService object, containing oauth consumer configuration
            OAuthService service = OAuthService.Create(
                new EndPoint(RequestTokenUrl, "POST"),         // requestTokenEndPoint
                new Uri(AuthorizationUrl),                     // authorizationUri
                new EndPoint(AccessTokenUrl, "POST"),          // accessTokenEndPoint
                true,                                          // useAuthorizationHeader
                "http://api.fitbit.com",                       // realm
                "HMAC-SHA1",                                   // signatureMethod
                "1.0",                                         // oauthVersion
                new OAuthConsumer(ConsumerKey, ConsumerSecret) // consumer
                );

            try
            {
                // Create OAuthRequest object, providing protected resource URL, consumer configuration,
                // callback URL and current session identifier
                OAuthRequest request = OAuthRequest.Create(
                    new EndPoint(ApiCallUrl, "GET"),
                    service,
                    this.Context.Request.Url,
                    this.Context.Session.SessionID);

                // Assign verification handler delegate
                request.VerificationHandler = AspNetOAuthRequest.HandleVerification;

                // Call OAuthRequest object GetResource method, which returns OAuthResponse object
                OAuthResponse response = request.GetResource();

                // Check if OAuthResponse object has protected resource
                if (!response.HasProtectedResource)
                {
                    // If not we are not authorized yet, build authorization URL and redirect to it
                    string authorizationUrl = service.BuildAuthorizationUrl(response.Token).AbsoluteUri;
                    Response.Redirect(authorizationUrl);
                }

                // Store the access token in session variable
                Session["access_token"] = response.Token;

                // Initialize the XmlDocument object and OAuthResponse object's protected resource to it
                this.Doc = new XmlDocument();
                this.Doc.Load(response.ProtectedResource.GetResponseStream());
            }
            catch (WebException ex)
            {
                Response.Write(ex.Message);
                Response.Close();
            }
            catch (OAuthRequestException ex)
            {
                Response.Write(ex.Message);
                Response.Close();
            }

 

 

Would anyone be able to point me in the right direction? Any help is appreciated.

 

Many thanks.

Best Answer
0 Votes
6 REPLIES 6

Have a look at a new branch Adam Storr and I are working on that is a new PCL compatible version that removes the dependecy on RestSharp. I think that's what is likely preventing you from using the current Fitbit .NET library. Also, this one is async, so you can call the FitbitClient methods without hanging up the UI thread:

 

https://github.com/aarondcoleman/Fitbit.NET/tree/async-portable 

 

Lastly, if you are feeling FOSS-y (is that a word?) and get it working on Windows Phone, we'd love a pull request that has a demo Windows Phone app since we already have a web app (ASP.NET MVC) and desktop (console). 

 

I have used this new version of the library in Xamarin development (iOS / Android) so I know it's pretty portable.

 

--Aaron

Using Fitbits in Research? Check out Fitabase --www.fitabase.com
Best Answer
0 Votes

Thanks for your reply Aaron. I've used some of the code from the Fitbit.NET API Client Library link you sent me to get it working with a Windows Phone project. It debugs fine, until it reaches

RequestToken token = a.GetRequestTokenAsync().Result;

It goes to the Authenticator class, method GetRequestTokenAsync() in the Fitbit.Portable project, and hangs at line

var tokenResponse = await authorizer.GetRequestToken(Constants.BaseApiUrl + Constants.TemporaryCredentialsRequestTokenUri);.

 

Here are parts of my solution below:

 

MainPage.xaml

public sealed partial class MainPage : Page
    {
        const string consumerKey = "my-consumer-key-is-here";
        const string consumerSecret = "my-consumer-secret-is-here";
        
        public MainPage()
        {
            this.InitializeComponent();

            this.NavigationCacheMode = NavigationCacheMode.Required;
        }

        /// <summary>
        /// Invoked when this page is about to be displayed in a Frame.
        /// </summary>
        /// <param name="e">Event data that describes how this page was reached.
        /// This parameter is typically used to configure the page.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            // TODO: Prepare page for display here.

            // TODO: If your application contains multiple pages, ensure that you are
            // handling the hardware Back button by registering for the
            // Windows.Phone.UI.Input.HardwareButtons.BackPressed event.
            // If you are using the NavigationHelper provided by some templates,
            // this event is handled for you.
        }

        static Task<AuthCredential> Authenticate()
        {
            /*var requestTokenUrl = "http://api.fitbit.com/oauth/request_token";
            var accessTokenUrl = "http://api.fitbit.com/oauth/access_token";
            var authorizeUrl = "http://www.fitbit.com/oauth/authorize";*/

            var a = new Fitbit.Api.Portable.Authenticator(consumerKey, consumerSecret);

            RequestToken token = a.GetRequestTokenAsync().Result;

            var url = a.GenerateAuthUrlFromRequestToken(token, false);

            Launcher.LaunchUriAsync(new Uri(url));

            // I'll sort out the below code later.

            //Debug.WriteLine("Enter the verification code from the website");
            //var pin = Console.ReadLine();

            //var credentials = a.GetAuthCredentialFromPinAsync(pin, token);
            //return credentials;

            return null;
        }

        // Button clicked on UI
        private void DoAPI(object sender, RoutedEventArgs e)
        {
            //Example of getting the Auth credentials for the first time by directoring the
            //user to the fitbit site to get a PIN. 

            AuthCredential credentials;

            credentials = Authenticate();

            var fitbit = new FitbitClient(consumerKey, consumerSecret, credentials.AuthToken, credentials.AuthTokenSecret);

            var profile = fitbit.GetUserProfile();
            Debug.WriteLine("Your last weight was {0}", profile.Weight);

            //Console.ReadLine();
        }
    }

Authenticator.cs

public class Authenticator
    {
        public string ConsumerKey { get; private set; }
        public string ConsumerSecret { get; private set; }

        public Authenticator(string consumerKey, string consumerSecret)
        {
            ConsumerKey = consumerKey;
            ConsumerSecret = consumerSecret;
        }

        public string GenerateAuthUrlFromRequestToken(RequestToken token, bool forceLogoutBeforeAuth)
        {
            var url = Constants.BaseApiUrl + (forceLogoutBeforeAuth ? Constants.LogoutAndAuthorizeUri : Constants.AuthorizeUri);
            return string.Format("{0}?oauth_token={1}", url, token.Token);
        }

        /// <summary>
        /// First step in the OAuth process is to ask Fitbit for a temporary request token. 
        /// From this you should store the RequestToken returned for later processing the auth token.
        /// </summary>
        /// <returns></returns>
        public async Task<RequestToken> GetRequestTokenAsync()
        {
            // create authorizer
            var authorizer = new OAuthAuthorizer(ConsumerKey, ConsumerSecret);

            // get request token
            var tokenResponse = await authorizer.GetRequestToken(Constants.BaseApiUrl + Constants.TemporaryCredentialsRequestTokenUri);
            var requestToken = tokenResponse.Token;

            // return the request token
            return new RequestToken
            {
                Token = requestToken.Key,
                Secret = requestToken.Secret
            };
        }

.......

Do you know what the problem could be? I can send you the whole solution if that helps. I'm guessing there may be deadlock somewhere due to the hanging/freezing.

 

Many thanks.

Best Answer
0 Votes

What's the specific error you're getting? I'm going to guess it's related to our use of AsyncOAuth which requires that you create a staticly compute hash once at the time of app load.

 

See how we do it for websites here:

https://github.com/aarondcoleman/Fitbit.NET/blob/async-portable/SampleWebMVC.Portable/Global.asax.cs

 

Specifically I'm talking about adding in these lines at the time your app first launches:

using System.Security.Cryptography;
using AsyncOAuth; //... //... OAuthUtility.ComputeHash = (key, buffer) => { using (var hmac = new HMACSHA1(key)) { return hmac.ComputeHash(buffer); } };

Hope that's the missing peice. We need to document this new wrapper library a lot better, I know that's going to be a common issue, although only until OAuth 2.0 is the default and then we don't really even need to rely on AsyncOAuth for their 1.0 implementation (though, the plan is now to support both specs fo a while so systems can be migrated and tokens can be exchanged).

 

--Aaron

 

 

Using Fitbits in Research? Check out Fitabase --www.fitabase.com
Best Answer
0 Votes

Hi Aaron,

 

There's no specific error shown. It just hangs at that same line, in the debug it shows "The thread 0x81c has exited with code 0 (0x0)." and similar lines like that every few seconds, and the UI is frozen (can't click the button or anything anymore).

 

I've added the code required for the compute hash you mentioned in my App.xaml.cs file where the app starts, with the help of this link: https://github.com/neuecc/AsyncOAuth/blob/master/README.md

Because

using System.Security.Cryptography;

isn't compatiable in Universal Store apps, I've used:

 

AsyncOAuth.OAuthUtility.ComputeHash = (key, buffer) =>
{
    var crypt = Windows.Security.Cryptography.Core.MacAlgorithmProvider.OpenAlgorithm("HMAC_SHA1");
    var keyBuffer = Windows.Security.Cryptography.CryptographicBuffer.CreateFromByteArray(key);
    var cryptKey = crypt.CreateKey(keyBuffer);

    var dataBuffer = Windows.Security.Cryptography.CryptographicBuffer.CreateFromByteArray(buffer);
    var signBuffer = Windows.Security.Cryptography.Core.CryptographicEngine.Sign(cryptKey, dataBuffer);

    byte[] value;
    Windows.Security.Cryptography.CryptographicBuffer.CopyToByteArray(signBuffer, out value);
    return value;
};

from the link instead of:

 

OAuthUtility.ComputeHash = (key, buffer) => { using (var hmac = new HMACSHA1(key)) { return hmac.ComputeHash(buffer); } };

Now, whenever I reach the line 

// get request token
            var tokenResponse = await authorizer.GetRequestToken(Constants.BaseApiUrl + Constants.TemporaryCredentialsRequestTokenUri);

 

It steps into the .ComputeHash function, and 

return value;

is returning "System.Byte[]", which doesn't seem right, and then the app hangs again as described at the top of this post. ("key" and "buffer" are also set to "System.Byte[]").

 

Do you know what the problem is now? And what the value of "value" should be?

Many thanks again.

 

Best Answer
0 Votes

Can you step through line-by-line and find the line that's hanging?

Using Fitbits in Research? Check out Fitabase --www.fitabase.com
Best Answer
0 Votes

Hi aaron, what callback url did you use for mobile apps? i tried [appname]://fitbit but it could not detect the name of my app while it is still under development. I'm doing a Windows 10 UWP and xamarin.ios and xamarin.android. thanks!

Best Answer
0 Votes