Tuesday, January 12, 2016

Fitbit, Unity, OAuth 2 and NATIVE browser...and about a week of cursing.

T.StartPost();

SO! I found out not too long after my last post that I (and everyone else using Fitbit data) would not longer be allowed to use Webview based solutions for gaining access to Fitbit data via OAuth 2.

This creates quite the predicament as when you're using Unity there's no Unity specific way of getting the OAuth return code from the browser (such as Chrome, Safari etc.)

This meant that I had to spend about the last week cursing while trawling the internet for solutions. Unfortunately there is a bunch but some of them do not seem to work. THANKFULLY, how ever, there is one that I found that DID work and I have to definitely give credit where credit is due and say that without Ofer Reichman's blog post I probably would not have gotten this to work.

You can pretty much follow his verbatim to get it working but I will also transcribe some small differences in things that work for Fitbit .  Also I'm working on refactoring my FitbitAPI class for Unity. I'm likely to just release it on Github for the betterment of the community and so others can help to make it better and learn from it as well.)

So without Further-Ado:

How to Do OAuth 2 authentication in Unity FOR Fitbit..With a Native Browser (Known to work with Android)


**If you want more in depth reading you can read Ofer's post but I'm just going to cover the nitty gritty of getting it to work with Fitbit**

Assumptions by me:
-You already have an app registered with Fitbit
-You already have Android SDK's installed
-You already have decent knowledge of Unity

I'm using :
Windows 10
Eclipse Juno (but shouldn't make a difference if you're using a higher version)
Unity 5




Hope this helps :) Feel free to comment and hopefully I can help (no promises though)

T.Out();

28 comments:

  1. Hi Travis,

    Thanks a lot for the guide. I've been trying to get the same thing working and for some reason I can't get the callback to be captured by my intent filter. I get redirected to https://www.fitbit.com/oauth2/mycustomscheme://oauth/callback/fitbit?code=authorization_code and then it just loads up a 404 error. Tried going through logcat to see if anything was getting called but couldn't see anything relating to this. Will keep fiddling with it.

    If you encountered a similar problem before getting to a working state I'd love to hear about it. I'm considering trying to have java initiate the request as well in hopes that it will be easier to capture the result that way or to see if I can then use a Chrome Custom Tab.

    I'm guessing I probably missed a small step so I'll probably try starting over again. Thanks again either way!

    ReplyDelete
  2. My assumption would be that your callback uri is
    https://www.fitbit.com/oauth2/mycustomscheme://oauth/callback/fitbit
    right?
    if so you probably need to change it to something more like
    mycustomscheme://oauth/callback/fitbit

    and you'll have your android Intent listening to mycustomscheme (which I actually advise that you change this to something more unique to your app)

    ReplyDelete
    Replies
    1. Thanks for getting back! I did use the current working title of my game as the scheme I was just putting it generically in my question.

      I registered my callback url as
      fitpet_android://oauth/callback/fitbit

      And I make the auth request with the url built as follows:

      AUTH_URL = "https://www.fitbit.com/oauth2/authorize",
      CALLBACK_URL = "fitpet_android://oauth/callback/fitbit",
      RESPONSE_TYPE = "code";

      private string BuildAuthUrl()
      {
      string AuthUrl = string.Format(
      "{0}?response_type={1}&client_id={2}&redirect_uri={3}&scope={4}",
      AUTH_URL, //0
      RESPONSE_TYPE, //1
      CLIENT_ID, //2
      WWW.EscapeURL(CALLBACK_URL), //3
      SCOPE); //4
      return AuthUrl;
      }


      When I call the url the browser opens it correctly shows my registered app info and I click to allow it then redirects to the url I posted (https://www.fitbit.com/oauth2/fitpet://oauth/callback/fitbit?code=authorization_code).

      Nothing happens beyond that. I tried following your tutorial and the one you referenced very closely and also messed around with the intent filter a bit after it wasn't working. Still no luck :(.

      My best guess is that my plugin isn't being used so I think I'll try to confirm that first. I feel like I'm probably missing something silly :)


      Delete
    2. I think this was because I decided to use an underscore in my scheme. I can finally move on!

      Wanted to say one more time that I appreciate you taking the time to get back to me and making this tutorial in the first place. Thanks!

      Delete
    3. Ah yeah that would probably do it too and it's not a problem. Gotta help out where I can :)

      Delete
  3. Sorry for asking, after I crtl+S, it doesn't generate .jar file in bin folder, and I debug it gives me error with "No compatible device instance was found to run com.Company.Fitbit.MainActivity". Is it the problem that I don't have a Android SDK installed?

    ReplyDelete
    Replies
    1. I'd assume so. To build stuff for Android AFAIK you have to have the android SDK's.

      Delete
  4. Sorry still not be able to create .jar in bin folder after I installed Android SDK.

    ReplyDelete
    Replies
    1. Hey man, I found this error.

      Description Resource Path Location Type
      Project 'appcompat_v7' is missing required source folder: 'gen' appcompat_v7 Build path Build Path Problem

      I have totally no idea with it.

      Delete
    2. After more try, and some trick for Eclipse, finally I get the .jar file, thanks a lot

      Delete
    3. No problem, Sorry I couldn't tell you what the problem was (I don't do much with Eclipse outside of making this small thing for Unity) Glad you got it working.

      Do you mind posting what you did to get it working for other future readers as well?

      Delete
    4. Sure, I would like to share information I got.

      Delete
    5. The problem itself is you losing of "appcompat_v7" this build, but it actually in your build. So how do you solve is

      1. File -> Import
      2. Select Android -> Existing Android Code Into Workplace.
      3. Browse
      4. Find the file should in Android\sdk\extras\android\support\v7\appcompat (If don't have, update your Android by Android SDK)
      5. After added on, should have a "android-support-v7-appcompat" in your file explorer.
      6. Right click select Properties.
      7. Select Java Build Path -> Libraries
      8. Press Add Library -> Android Classpath Container -> select "android-support-v7-appcompat" -> Finish
      9. Most magic part in Ecplise, select Project -> Clean the require project -> Rebuild the require project. (Remember to uncheck auto build in Project)

      Delete
    6. Sorry, for the part 4. update your Android should be """Android Manager""" which is located in your Android/sdk folder

      Delete
  5. Hi,

    I got something like

    https://www.fitbit.com/oauth2/authorize?response_type=token&client_id=XXXXX&redirect_uri=https%3a%2f%2fwww.google.com&scope=activity%20profile

    I use https://www.google.com as redirect url, and I got the access token from the site, but after that I don't know what to do with further code

    By using the OAuth2.0 tutorial page can get data, but what to do with Unity, I have no idea with that...

    And the method I using is from the comment =.=

    ReplyDelete
    Replies
    1. http://technicalartistry.blogspot.ca/2016/09/unity-fitbit-class-finally-online.html

      Here's the class I should have refactored a while back. It might still need tweaking but should at least get you started :)

      Delete
  6. Is it even possible to use custom schemes anymore? I'm trying a test run with instagram, before fitbit, and the instagram website now refused to allow schemes that aren't http:// or https://

    ReplyDelete
    Replies
    1. In some cases it is not possible (for example, the Nike bands API won't allow custom schemes but Fitbit still does.) It's on a per API basis.

      Delete
    2. Cool. I almost have it working. In the Editor, it brings up the "give fitbit permission" page, but then asks me to pick some kind of app to read the custom scheme callback when I click on Okay. But when I try to build an apk, it gives me this error:
      __
      CommandInvokationFailure: Failed to re-package resources.
      C:\Users\Michael\Documents\SDKs\sdk\build-tools\23.0.2\aapt.exe package --auto-add-overlay -v -f -m -J gen -M AndroidManifest.xml -S "res" -I "C:/Users/Michael/Documents/SDKs/sdk\platforms\android-23\android.jar" -F bin/resources.ap_ --extra-packages

      stderr[
      ERROR: No argument supplied for '--extra-packages' option

      Delete
    3. No clue, never seen the error before unfortunately.
      http://answers.unity3d.com/questions/849592/error-building-player-commandinvokationfailure-fai-5.html
      Try this maybe? Seems like most people getting this error don't have the google play stuff

      Delete
    4. Yeah, it was that, plus I also had to put the package name in one of the Android Manifest files (the one in the OAuth folder, I think). Thanks! Last question: do you know if anything has happened with an iOS version? Mainly asking on behalf of my company, since we're trying to build a multi platform app that works with Fitbit using Unity.

      Delete
  7. Addendum: has anyone has issues with the return code being reported as invalid? I have. The trace log confirms that _returnCode is being given, then after "return code isn't empty" and "waiting for access token", I get an error saying the authorization code is invalid and showing me the exact return code that it gave me earlier. I did put the client secret and client ID into the private variables as specified (much to the annoyance of our back end guy, but that's another story)

    ReplyDelete
    Replies
    1. I'm wondering if I should be replacing "access_code" with something else, but when I try that, it gives me a different error saying unsupported_grant_type.

      Delete
    2. No, that was a dumb suggestion on my part; just realized what that field meant and how it worked. FIXED: The issue was that some junk was being returned at the end of the return code that the code hasn't yet accounted for -- a #, followed by some underscores. I did this and it seems to work now and return an access token:
      _returnCode = code.Substring(CustomAndroidScheme.Length + 6);
      _returnCode = _returnCode.Split ('#') [0];

      Delete
  8. Hi Travis,

    Great video, you really explained things well and I got it to work!

    Unfortunately I'm having crashes like you said upon my app returning from the fitbit auth in browser to unity. This started happening when I added a new plugin from the asset store that also used the main activity in the manifest file. Because of this I had to tweak about with the manifest files to get the game to even compile.

    But now I have these crashes and I need the new plugin. Do you have any ideas? I assume it's to do with plugin conflicts and messed up manifests? I have been looking at this http://eppz.eu/blog/unity-android-plugin-tutorial-1/ link to try and avoid conflicts.
    Can you even use Fragments to do what this plugin you have written does? I'm very inexperienced with Android so any help is appreciated!

    ReplyDelete
    Replies
    1. Hey there,

      Unfortunately I'm pretty noob at native Android as well so I'm not likely to be a lot of help for this.
      I'm not sure if you can just use a fragment or not. The only way I got it working was how I described in the video.

      Delete
    2. Hey,

      Thanks for getting back, I feel like I've been bashing my head into a wall! That's grand, cheers for your videos, they're incredibly helpful!

      Delete
  9. hi have you done for microsoft azure ad before?

    ReplyDelete

Hey, I love to have feedback about either how the post was or if there's even a topic you want me to talk about/tutorial, so let me know and I'll see what I can do. We only grow if we grow together.