Giter Club home page Giter Club logo

fitbitter's Introduction

fitbitter

A Flutter package to make your life easier when dealing with Fitbit APIs.

Getting started

Step 1: Install Fitbitter

To install Fitbitter, simply add fitbitter: to the dependencies of your pubspec.yaml file:

dependencies:
    fitbitter: #latest version

Step 1a: (for Android only) Modify you manifest

Fitbitter uses flutter_web_auth to let you authenticate to Fitbit. In Android, you need to add these lines of code to your android/app/src/main/AndroidManifest.xml file:

<activity android:name="com.linusu.flutter_web_auth.CallbackActivity"
    android:exported="true">
      <intent-filter android:label="flutter_web_auth">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="CALLBACK_SCHEME" />
      </intent-filter>
    </activity>

and change CALLBACK_SCHEME with your callback scheme (in the test example below this will be example)

Step 1b: (for Android only) Increase the minimum Android SDK version

Fitbitter uses flutter_secure_storage to securely store the Fitbit tokens. Since flutter_secure_storage requires that minimum Android SDK version is 18, you need to change the default minimum sdk version to 18 or above. To do so, open android/app/build.gradle, locate this snippet of code:

...
defaultConfig {
        applicationId "your.app.id"
        minSdkVersion flutter.minSdkVersion
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
...

and change minSdkVersion to 18 or above, e.g.,:

...
defaultConfig {
        applicationId "your.app.id"
        minSdkVersion 18
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
...

Step 1c: (for Android only) Requirement: Web Browser

Fitbitter uses flutter_web_auth to let you authenticate to Fitbit. In order to let it work correcty please be sure that your emulator or your physical device is using Chrome, Opera, or Firefox as default web browser.

Step 1d:(for Web only) Requirement: Create an endpoint

Fitbitter uses flutter_web_auth to let you authenticate to Fitbit. In order to let it work correcty, as indicated in https://pub.dev/packages/flutter_web_auth, on the Web platform an endpoint needs to be created that captures the callback URL and sends it to the application using the JavaScript postMessage() method. In the ./web folder of the project, create an HTML file with the name e.g. auth.html with content:

<!DOCTYPE html>
<title>Authentication complete</title>
<p>Authentication is complete. If this does not happen automatically, please
close the window.
<script>
  window.opener.postMessage({
    'flutter-web-auth': window.location.href
  }, window.location.origin);
  window.close();
</script>

Redirection URL passed to the authentication service must be the same as the URL on which the application is running (schema, host, port if necessary) and the path must point to created HTML file, /auth.htmlin this case. The callbackUrlScheme parameter of the authenticate() method does not take into account, so it is possible to use a schema for native platforms in the code.

For the Sign in with Apple in web_message response mode, postMessage from https://appleid.apple.com is also captured, and the authorization object is returned as a URL fragment encoded as a query string (for compatibility with other providers).

Step 2: Test Fitbitter

Once installed, it is time to test drive Fitbitter. In this example, we will use Fitbitter to authenticate our app into Fitbit APIs and simply fetch yesterday's step count.

Preliminary requirement: Register your app

To be able to perform any operation with the Fitbit APIs, you must register first your application in the developer portal of Fitbit and obtain two IDs, namely the "OAuth 2.0 Client ID" and the "Client Secret". To do so, you have to follow these steps.

  • Create a Fitbit account, if you do not have one.

  • Register a new app at https://dev.fitbit.com/apps/new. The form will look like this: Fitbit App Registration Form

  • Choose an "Application Name" (e.g., "Example").

  • Set a brief "Description" (e.g., "Just a simple test of an awesome package.")

  • Set the "Application Website". It can be random for the purpose of testing the example so let's put https://www.example.com/.

  • Set an "Organization" (e.g., "Myself").

  • Set an "Organization Website". It can be random for the purpose of testing the example so let's put https://www.myself.com/.

  • Set a "Terms of Service Url". It can be random for the purpose of testing the example so let's put https://www.myself.com/tos.

  • Set an "Privacy Policy Url". It can be random for the purpose of testing the example so let's put https://www.myself.com/pp.

  • Set the "Application Type" to "Client".

  • Choose a Callback URL" (e.g., "example://fitbit/auth").

  • Choose a "Default Access Type" (e.g., "Read-Only").

  • Check the "I have read and agree to the terms of service" box.

  • Click the "Register" button. You should now see the "OAuth 2.0 Client ID" and the "Client Secret" strings provided by Fitbit.

App authentication

You are now ready to authorize your application.

To do that, simply call the asynchronous method FitbitConnector.authorize(), within your code, as:

    FitbitCredentials? fitbitCredentials =
        await FitbitConnector.authorize(
            clientID: Strings.fitbitClientID,
            clientSecret: Strings.fitbitClientSecret,
            redirectUri: Strings.fitbitRedirectUri,
            callbackUrlScheme: Strings.fitbitCallbackScheme
        );

This will open a web view where user will be able to input his Fitbit credentials and login. After the login, the web view will close and the method will return a FitbitCredentials? instance that contains the credentials to be used to make requests to the Fitbit Web API via fitbitter. In particular, fitbitCredentials.userID contains the Fitbit user id of the user that just authorized fitbitter, fitbitCredentials.fitbitAccessToken contains the Fitbit access token, and fitbitCredentials.fitbitRefreshToken contains the Fitbit refresh token.

::: warning Since version 2.0.0, fitbitter no longer stores the credentials automatically. As such, you, as a developer, must manage such crendentials according to your strategy. :::

Fetch step count data

With your app authorized, you are now ready to fetch data from Fitbit. In this example, we will fetch yesterday's step count.

Using Fitbitter, this is very easy. First instanciate a FitbitActivityTimeseriesDataManager of type: 'steps':

    FitbitActivityTimeseriesDataManager
        fitbitActivityTimeseriesDataManager =
        FitbitActivityTimeseriesDataManager(
            clientID: '<OAuth 2.0 Client ID>',
            clientSecret: '<Client Secret>',
            type: 'steps', 
        );

Then fetch the desired data using the fetch method of FitbitActivityTimeseriesDataManager with the proper FitbitActivityTimeseriesAPIURL:

final stepsData = await fitbitActivityTimeseriesDataManager.fetch(
    FitbitActivityTimeseriesAPIURL.dayWithResource(
        date: DateTime.now().subtract(Duration(days: 1)),
        userID: fitbitAccount.id,
        resource: fitbitActivityTimeseriesDataManager.type,
        fitbitCredentials: fitbitCredentials!,
        )
    ) as List<FitbitActivityTimeseriesData>;

That's it!

::: tip For more information on Fitbitter functionalities, check out the Guides and the Fitbitter Reference API :::

Documentation & Guides

For more docs and guides please refer to: https://gcappon.github.io/fitbitter/.

Support

If you like my work, feel free to support me with a coffee. Thanks!

"Buy Me A Coffee"

fitbitter's People

Contributors

fraca98 avatar gcappon avatar mazzonem avatar rufinosalgado21 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

fitbitter's Issues

No output shown

Hi, sorry for asking a lot of questions. I really need the help here. Somehow the example app code is working but the problem is that it's not displaying any fetched data on the home page. Please help me.

"LateInitializationError: Local 'response' has not been initialized". when using isTokenValid

Hi there,

I get and check the Fitbit creds like so:

  /// get credentials, if not exist, get new ones
  Future<FitbitCred> getFitbitCreds({required int userId, required int programId}) async {
    var entryBox = await Hive.openBox<FitbitCred>('fitbit_cred_container');
    FitbitCred validCreds;
    // if doesnt exist, return false
    if (entryBox.isEmpty) {
      // get new creds
      FitbitCredentials? fitbitCreds = await FitbitConnector.authorize(
        clientID: fitbitClientID,
        clientSecret: fitbitClientSecret,
        redirectUri: fitbitRedirectUri,
        callbackUrlScheme: fitbitCallbackScheme,
      );

      FitbitCred newCreds = FitbitCred(
        fitbitAccessToken: fitbitCreds!.fitbitAccessToken,
        fitbitRefreshToken: fitbitCreds.fitbitRefreshToken,
        userID: fitbitCreds.userID,
        lastSync: DateTime.now(),
      );
      await entryBox.put('curr_fitbit_cred', newCreds);
      validCreds = newCreds;
    } else {
      // get the creds and return it
      FitbitCred existingCreds = entryBox.get('curr_fitbit_cred')!;
      validCreds = existingCreds;
    }

    // check if they are valid
    bool valid = await FitbitConnector.isTokenValid(
        fitbitCredentials: FitbitCredentials(
      fitbitAccessToken: validCreds.fitbitAccessToken,
      fitbitRefreshToken: validCreds.fitbitRefreshToken,
      userID: validCreds.userID,
    ));

    if (valid) {
      return validCreds;
    } else {
      //do something else
    }

    return validCreds;
  }

Seems like it's coming from:

VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: LateInitializationError: Local 'response' has not been initialized.
#0      LateError._throwLocalNotInitialized (dart:_internal-patch/internal_patch.dart:197:5)
#1      FitbitConnector.isTokenValid (package:fitbitter/src/fitbitConnector.dart:140:16)
<asynchronous suspension>

Sometimes it works well, but sometimes I get LateInitializationError: Local 'response' has not been initialized at the check.

Am I doing something wrong?

Any guidance is appreciated!

correct format of callbackUrlScheme

Hi - I am mostly leaving this here to help the unwary after blundering around in the dark for a while. Maybe others implicitly realised this but I didn't.

If you follow the example file here or many of the OAuth tutorials on the web you will probably try to use your app ID or CFBundleID as your callbackUrlScheme. I did but I kept getting the error that my callbackUrlScheme was incorrect.

If you follow the code through to where that error comes from the web_auth package checks it against the following regular expression

static RegExp _schemeRegExp = new RegExp(r"^[a-z][a-z0-9+.-]*$");

Which essentially says the first character should be lowercase a-z and there can be any number of subsequent characters that are either a lowercase a-z, or 1-9 or . or + or -

this means anything with a captial such as camelCase or with_underscores will fail the check.

Android studio (and maybe VSCode but I don't use it) will force you to use a project_name_with_underscores when you set up a new project and will helpfully insert this into your info.plist as your CFBundleID, which if your a halfwit like me, you will then jutifully copy into your code and bang your head against a wall for an hour or so....

Hard coded scope

Hello,

When using the method FitbitConnector.authorize, the scope is hard coded in the fitbitAuthAPIURL file. Would it be possible to have it as a parameter so that it can be changed by the user when needed ? Because our app doesn't need all scopes.

Best regards.

How to use

Hi, im kinda confused in how to use this package actually. Example have one app then lib also have some packages inside. So can u help guide me through on how to start the implementation?
Second fitbitter is for fitbit web API right?

README update for android developers.

Hi, hope im not intruding, but I have been trying to use your software for a few days, and have been struggling. I realised that this issue is just for when running on android.

If you want to run this code on android you need to update your manifest with another activity.

so in example/android/app/src/main/AndroidManifest.xml

you add this activity

<activity android:name="com.linusu.flutter_web_auth.CallbackActivity" >
      <intent-filter android:label="flutter_web_auth">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="YOUR_CALLBACK_URL_SCHEME_HERE" />
      </intent-filter>
    </activity>

in this example you would replace YOUR_CALLBACK_URL_SCHEME_HERE with example

Cant add package

HI when I add the dependency and try to run my code I get this error

FAILURE: Build failed with an exception.

  • What went wrong:
    Execution failed for task ':flutter_web_auth:processDebugManifest'.

Failed to calculate the value of task ':flutter_web_auth:processDebugManifest' property 'packageOverride'.
Failed to query the value of property 'applicationId'.
org.xml.sax.SAXParseException; systemId: file:/C:/Users/user/Downloads/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_web_auth-0.4.1/android/src/main/AndroidManifest.xml; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.

I changes the minsdk and added the requires in android manifest

Web View not closing after successful Authentication

I have successfully integrated Fitbitter and the login and subsequent permission page, the app is redirecting to the redirection url. I am also getting the Authorization Code through Uni Link stream listener.

But everything is happening in background while the web view stays at the top. It never closes and Fitbit.com permission page comes back again. Is there any way to close the WebView after successful authentication. I am on a 7th generation iPad
unnamed
.

Getting Weight Data

Hi, will there an update to include more Data types from Fitbit? (E.g: Weight, food logs, ... )

eror

how can i run this code in vs code?? kindly help me

Error when you don't have data on FitbitCardioScoreData

I think this piece of the code might have not been yet moved to null safety, specifically on the file: fitbitCardioScoreDataManager.dart

In these lines

image

I'm getting the next exception:

image

And I'm aware that I don't have data on this metric on my Fitbit, but the package should also handle that case? I think there might be other instances where this also happens?

Error thrown on FitbitDataManager.fetch()

The Fitbitter throws an exception on the following code:

          icon: Icon(Icons.device_thermostat),
          iconSize: 50,
          onPressed: () async {
            var startDate = DateTime.now().subtract(Duration(days: 18));
            var endDate = DateTime.now();

            var userId = await FitbitConnector.authorize(
              context: context,
              clientID: APIKeys.fitbitClientID,
              clientSecret: APIKeys.fitbitClientSecret,
              callbackUrlScheme: APIKeys.fitbitCallbackScheme,
              redirectUri: APIKeys.fitbitRedirectUri,);

            var fitbitActivityTimeseriesDataManager =
            FitbitActivityTimeseriesDataManager
            (clientID: APIKeys.fitbitClientID,
            clientSecret: APIKeys.fitbitClientSecret,
                type: "calories",);


            var rawData = await fitbitActivityTimeseriesDataManager.fetch(
                FitbitActivityTimeseriesAPIURL.dateRangeWithResource(
              userID: userId,
              startDate: startDate,
              endDate: endDate,
              resource: "calories",),)
            as List<FitbitActivityTimeseriesData>;

            print(rawData);
            //Navigator.pushNamed(context, AllDevices.routeName);
          },

The following error is thrown:
Failed assertion: line 315 pos 7: 'instanceFactory != null': Object/factory with type SharedPreferences is not registered inside GetIt. (Did you accidentally do GetIt sl=GetIt.instance(); instead of GetIt sl=GetIt.instance; Did you forget to register it?) #0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:46:39) #1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:36:5) #2 _GetItImplementation._findFactoryByNameAndType (package:get_it/get_it_impl.dart:315:7) #3 _GetItImplementation.get (package:get_it/get_it_impl.dart:336:29) #4 _GetItImplementation.call (package:get_it/get_it_impl.dart:373:12) #5 new FitbitAuthAPIURL.isTokenValid (package:fitbitter/src/urls/fitbitAuthAPIURL.dart:112:34) #6 FitbitConnector.isTokenValid (package:fitbitter/src/fitbitConnector.dart:73:40) #7 FitbitDataManager._checkAccessToken (package:fitbitter/src/managers/fitbit<โ€ฆ>

Since the code resembles the example on GitHub as much as possible this shouldn't be the case.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.