From 5e9182a227662cc58d688274aa23e1936468b747 Mon Sep 17 00:00:00 2001 From: Serdar Coskun Date: Mon, 1 Jun 2026 23:29:33 +0300 Subject: [PATCH] Rewrite README for a proper open-source landing page The old README was stale (referenced a removed Strava()/isInDebug API, a "heavy refactoring" warning, and outdated endpoint names). Replace with an accurate, structured README: - Badges (pub, CI, license), feature overview, table of contents - Quick start using the real StravaClient + repository API - Android/iOS setup, authentication + scopes, token refresh notes - Making calls (repository table + examples), Fault error handling - Collapsible supported-endpoints list matching the current API - Example explorer app instructions, contributing, acknowledgements, license Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 390 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 278 insertions(+), 112 deletions(-) diff --git a/README.md b/README.md index 8682dc2..db15062 100644 --- a/README.md +++ b/README.md @@ -1,160 +1,326 @@ -# strava_flutter +# strava_client +[![pub package](https://img.shields.io/pub/v/strava_client.svg)](https://pub.dev/packages/strava_client) [![CI](https://github.com/dreampowder/strava_flutter/actions/workflows/ci.yml/badge.svg)](https://github.com/dreampowder/strava_flutter/actions/workflows/ci.yml) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) -Dart/flutter package to use Strava API v3 +An unofficial Flutter client for the [Strava V3 API](https://developers.strava.com/docs/reference/). -Follow the "new" Authentication process +It handles the OAuth2 flow (including the native Strava app on iOS), automatic +token storage and refresh, and gives you typed models and repositories for the +Strava endpoints. -https://developers.strava.com/docs/authentication/ +- 🔐 OAuth2 authentication with automatic token refresh +- 🧩 Typed request/response models (generated with `json_serializable`) +- 🗂️ Repository-per-domain API (athletes, activities, segments, …) +- ⚠️ Structured error handling via `Fault` +- 📖 Bundled, validated [OpenAPI specs](openapi/) for the Strava API -##Warning: This package is under heavy refactoring, there might be breaking changes in the following updates. +> Looking for a hands-on tour? The [example app](example/) is an interactive +> API explorer that lets you log in and run every call against your account. -## API currently supported: +## Table of contents -### Authentication -- authorize -- deauthorize +- [Installation](#installation) +- [Quick start](#quick-start) +- [Platform setup](#platform-setup) +- [Authentication](#authentication) +- [Making API calls](#making-api-calls) +- [Error handling](#error-handling) +- [Supported endpoints](#supported-endpoints) +- [Example app](#example-app) +- [Contributing](#contributing) +- [Acknowledgements](#acknowledgements) +- [License](#license) -### Athlete related APIs -- getLoggedInAthlete -- updateLoggedInAthlete (scope profile:write) -- getLoggedInAthleteActivities (not limited) -- getLoggedInAthleteZones -- getGearById -- getStats -### Club related APIs -- getClubById -- getClubActivitiesById -- getClubMembersById -### Race related APIs -- getRunningRaces -- getRunningRaceById -### Activity related APIs -- createActivity -- uploadActivity (includes getUploadById) -Tested on TCX and GPX +## Installation -To generate TCX you can use the following package -https://pub.dev/packages/rw_tcx +Add the package: -### Segments related APIs -- getSegmentById -- getLoggedInAthleteStarredSegments -- getLeaderboardBySegmentId (not limited) -- starSegment - - -## How to install -Check on pub.dev/packages to see how to install this package - -https://pub.dev/packages/strava_client/install +```bash +flutter pub add strava_client +``` -### Additional steps when running on Android Pie 9.0 (API level 28) +or in `pubspec.yaml`: -The webview returned by the auth process may throw `net::ERR_CLEARTEXT_NOT_PERMITTED`. In this case add `android:usersCleartextTraffic="true"` to `the AndroidManifest.xml` like below: +```yaml +dependencies: + strava_client: ^2.3.0 +``` +Requires Dart `>=3.8.0`. + +## Quick start + +```dart +import 'package:strava_client/strava_client.dart'; + +final stravaClient = StravaClient( + clientId: "YOUR_CLIENT_ID", + secret: "YOUR_CLIENT_SECRET", +); + +Future main() async { + // 1. Authenticate (opens the Strava login / consent screen). + final token = await stravaClient.authentication.authenticate( + scopes: [ + AuthenticationScope.profile_read_all, + AuthenticationScope.read_all, + AuthenticationScope.activity_read_all, + ], + redirectUrl: "stravaflutter://redirect", + callbackUrlScheme: "stravaflutter", + ); + print("Access token: ${token.accessToken}"); + + // 2. Call the API — the token is attached (and refreshed) automatically. + final athlete = await stravaClient.athletes.getAuthenticatedAthlete(); + print("Hello ${athlete.firstname}!"); +} ``` - - ``` +Create the client **once** and reuse it (it wires up shared session state). -## How to use it +## Platform setup -1 -Get the client secret in your Strava settings related to your app https://www.strava.com/settings/api with "Authorization Callback Domain" set to "redirect" +The redirect URL scheme used in the snippets below is `stravaflutter://redirect`. +In your [Strava API settings](https://www.strava.com/settings/api) set the +**Authorization Callback Domain** to `redirect`. +### Android -2 - Settings of the url scheme for Strava Authentication redirect url -a) For Android -Add the following lines in your AndroidManifest.xml (in android/app/src/) -``` - +Add the callback activity to `android/app/src/main/AndroidManifest.xml`: + +```xml - - - - - - - + android:name="com.linusu.flutter_web_auth_2.CallbackActivity" + android:exported="true"> + + + + + + ``` -3 - set `android:launchMode="singleTop"` and remove any `android:taskAffinity` entries. +Set `android:launchMode="singleTop"` on your main activity and remove any +`android:taskAffinity` entries. +> On Android 9 (API 28) the auth webview can throw +> `net::ERR_CLEARTEXT_NOT_PERMITTED`. If so, add +> `android:usesCleartextTraffic="true"` to your `` tag. -b) for iOS -Add the following lines in your info.plist (in ios/Flutter/Runner/) -``` +### iOS + +Add the URL scheme to `ios/Runner/Info.plist`: + +```xml CFBundleURLTypes - - - CFBundleTypeRole - Editor - CFBundleURLName - stravaflutter - CFBundleURLSchemes - - stravaflutter - - - + + + CFBundleTypeRole + Editor + CFBundleURLName + stravaflutter + CFBundleURLSchemes + + stravaflutter + + + ``` -Also for launching the Native Strava app for Authenticate +To let users authenticate through the native Strava app when installed, also add: - -``` - LSApplicationQueriesSchemes - - strava - +```xml +LSApplicationQueriesSchemes + + strava + ``` +> The web platform is not supported (the OAuth redirect does not return to the +> app). Use Android or iOS. -4 - Create a file secret.dart and put in this file: -final String secret = "[Your client secret]"; -final String clientId = "[Your appID]"; +## Authentication -5 - import 'secret.dart' when you need secret and clientId in Strava API +```dart +// Authenticate. If a valid token is already stored it is reused; an expired +// token is refreshed automatically. +final TokenResponse token = await stravaClient.authentication.authenticate( + scopes: [AuthenticationScope.activity_read_all], + redirectUrl: "stravaflutter://redirect", + callbackUrlScheme: "stravaflutter", + forceShowingApproval: false, // force the consent screen even if already granted + preferEphemeral: true, // iOS: don't share cookies with Safari +); +// Revoke access and clear the stored token. +await stravaClient.authentication.deAuthorize(); +``` -6 - To see debug info in Strava API, set isInDebug to true in Strava() init +Available scopes (`AuthenticationScope`): `read`, `read_all`, +`profile_read_all`, `profile_write`, `activity_read`, `activity_read_all`, +`activity_write`. + +### Token storage & refresh + +Tokens are persisted with `shared_preferences` and reused across launches. On +every authenticated request the client checks expiry and **transparently +refreshes** the access token using the stored refresh token, so you don't have +to manage refresh yourself. + +## Making API calls + +Calls are grouped into repositories on the client: + +| Getter | Repository | +|--------|------------| +| `stravaClient.authentication` | OAuth | +| `stravaClient.athletes` | Athlete | +| `stravaClient.activities` | Activities | +| `stravaClient.clubs` | Clubs | +| `stravaClient.gears` | Gear | +| `stravaClient.routes` | Routes | +| `stravaClient.runningRaces` | Running races | +| `stravaClient.segments` | Segments | +| `stravaClient.segmentEfforts` | Segment efforts | +| `stravaClient.streams` | Streams | +| `stravaClient.uploads` | Uploads | + +```dart +// Recent activities +final activities = await stravaClient.activities.listLoggedInAthleteActivities( + DateTime.now(), // before + DateTime.now().subtract(Duration(days: 30)), // after + 1, // page + 30, // per page +); + +// A detailed segment +final segment = await stravaClient.segments.getSegment(229781); + +// Activity streams keyed by type +final streams = await stravaClient.streams.getActivityStreamsByType( + 12345678, + ["distance", "heartrate", "watts"], +); +``` -7 - Please check these examples for the moment +## Error handling -https://github.com/dreampowder/strava_flutter/tree/master/example +Failed requests throw a typed `Fault`: -https://github.com/dreampowder/strava_flutter/blob/master/example/lib/main.dart +```dart +try { + await stravaClient.athletes.getAuthenticatedAthlete(); +} on Fault catch (fault) { + print("message: ${fault.message}"); + for (final e in fault.errors ?? []) { + print(" ${e.resource}.${e.field}: ${e.code}"); + } +} +``` -If you have any problem or need an API not yet implemented please post a new issue +## Supported endpoints + +
+Athlete + +- `getAuthenticatedAthlete` +- `getAthleteZones` (heart-rate & power zones) +- `getAthleteStats` +- `updateAthlete` +
+ +
+Activities + +- `getActivity` +- `listLoggedInAthleteActivities` +- `listActivityComments` +- `listActivityKudoers` +- `getLapsByActivityId` +- `getActivityZones` +- `createActivity` +- `updateActivity` +
+ +
+Clubs + +- `getClub` +- `getLoggedInAthleteClubs` +- `listClubActivities` +- `listClubAdministrators` +- `listClubMembers` +
+ +
+Gear / Routes / Running races + +- `gears.getGearById` +- `routes.getRoute`, `routes.listAthleteRoutes`, `routes.exportRouteGPX`, `routes.exportRouteTCX` +- `runningRaces.listRunningRaces`, `runningRaces.getRage` +
+ +
+Segments & efforts + +- `segments.getSegment` +- `segments.listStarredSegments` +- `segments.exploreSegments` +- `segments.getLeaderBoard` +- `segments.starSegment` +- `segmentEfforts.getSegmentEffort`, `segmentEfforts.listSegmentEfforts` +
+ +
+Streams & uploads + +- `streams.getActivityStreams` / `getActivityStreamsByType` +- `streams.getRouteStreams` / `getRouteStreamsByType` +- `streams.getSegmentStreams` / `getSegmentStreamsByType` +- `streams.getSegmentEffortStreams` / `getSegmentEffortStreamsByType` +- `uploads.uploadActivity`, `uploads.getUpload` +
+ +To upload activities you can generate TCX files with the +[`rw_tcx`](https://pub.dev/packages/rw_tcx) package. + +Missing an endpoint? [Open an issue](https://github.com/dreampowder/strava_flutter/issues) +or send a PR — the repository pattern makes new calls easy to add. + +## Example app + +The [`example/`](example/) directory is a full **API Explorer**: log in with +OAuth, pick any call from a grouped list, fill in its parameters, and see the +pretty-printed JSON response (or `Fault`). + +```bash +cd example +cp lib/secret.dart.example lib/secret.dart # add your clientId + secret +flutter run +``` +## Contributing -## Tested on: -- Android 7, 8.0.0, 9.0, 10 -- iOS 12.1, 13.2, 13.3.1 -- NOT working yet on web (Auth problem, not coming back to initial page) +Contributions are welcome! Please: +1. Open an issue for bugs or feature requests. +2. For PRs: keep changes backwards compatible where possible, run + `dart analyze` and `flutter test`, and add tests where it makes sense. -## Contributors welcome! -If you spot a problem/bug or if you consider that the code could be better please post an issue. -I am not planning to implement all the Strava APIs, because I dont need all of them in my dev. -But let me know if you need some APIs that are not in the current list and I will add it. -Alternatively, you can easily implement additional API and I will add it to strava_futter. +CI runs analysis and tests on every PR. +## Acknowledgements -## Thanks -- Thanks to @Birdyf for developing this package at first place. -- Thanks to Joe Birch, I used his code to better understand Oauth process https://github.com/hitherejoe/FlutterOAuth -- Javier for https://javiercbk.github.io/json_to_dart/ +- [@Birdyf](https://github.com/Birdyf) for the original package. +- [Joe Birch](https://github.com/hitherejoe/FlutterOAuth) — OAuth reference. +- Strava's published [Swagger spec](https://developers.strava.com/swagger/), + bundled and validated under [`openapi/`](openapi/). +## License -## License: -strava_flutter is provided under a MIT License. Copyright (c) 2019-2020 Patrick FINKELSTEIN +[MIT](LICENSE) — Copyright (c) 2019-present the strava_flutter contributors.