Flutter Strava API集成插件strava_client的使用

发布于 1周前 作者 songsunli 来自 Flutter

Flutter Strava API集成插件strava_client的使用

概述

strava_flutter 是一个用于在Dart/Flutter项目中调用Strava API v3的包。它遵循最新的认证流程,允许开发者轻松地与Strava的各种API进行交互。

警告: 该包正在经历大规模重构,未来更新可能会引入破坏性变更。

支持的API

认证相关API

  • authorize
  • deauthorize

运动员相关API

  • getLoggedInAthlete
  • updateLoggedInAthlete (需要profile:write权限)
  • getLoggedInAthleteActivities
  • getLoggedInAthleteZones
  • getGearById
  • getStats

俱乐部相关API

  • getClubById
  • getClubActivitiesById
  • getClubMembersById

赛事相关API

  • getRunningRaces
  • getRunningRaceById

活动相关API

  • createActivity
  • uploadActivity(包括getUploadById

    测试了TCX和GPX格式的支持

为了生成TCX文件,可以使用 rw_tcx 包。

段落相关API

  • getSegmentById
  • getLoggedInAthleteStarredSegments
  • getLeaderboardBySegmentId
  • starSegment

安装方法

请参考 pub.dev 上提供的安装指南。

Android Pie (9.0, API level 28) 额外步骤

如果遇到net::ERR_CLEARTEXT_NOT_PERMITTED错误,请在AndroidManifest.xml中添加如下配置:

<application
    ...
    android:usesCleartextTraffic="true"
    ...>

使用说明

  1. 在Strava设置页面获取客户端密钥,并将“Authorization Callback Domain”设为redirect

  2. 设置URL Scheme以便处理来自Strava认证的重定向URL:

    • 对于Android,在AndroidManifest.xml中添加以下代码:
      <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="stravaflutter" android:host="redirect" />
      </intent-filter>
      
      同时修改launchModesingleInstance以确保Firefox下的正常工作。
    • 对于iOS,在info.plist中添加以下内容:
      <key>CFBundleURLTypes</key>
      <array>
        <dict>
          <key>CFBundleTypeRole</key>
          <string>Editor</string>
          <key>CFBundleURLName</key>
          <string>stravaflutter</string>
          <key>CFBundleURLSchemes</key>
          <array>
            <string>stravaflutter</string>
          </array>
        </dict>
      </array>
      
      如果需要启动本地Strava应用进行认证,还需添加:
      <key>LSApplicationQueriesSchemes</key>
      <array>
        <string>strava</string>
      </array>
      
  3. 创建secret.dart文件并保存您的client secretappID

    final String secret = "[Your client secret]";
    final String clientId = "[Your appID]";
    
  4. 在需要使用这些值的地方导入secret.dart

  5. 若要查看调试信息,可以在初始化StravaClient时将isInDebug设为true

  6. 参考示例代码了解具体用法。

示例代码

下面是一个简单的Flutter应用程序示例,演示了如何使用strava_flutter进行用户登录、登出以及显示访问令牌:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:strava_client/strava_client.dart';
import 'secret.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Strava Flutter',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: StravaFlutterPage(),
    );
  }
}

class StravaFlutterPage extends StatefulWidget {
  @override
  _StravaFlutterPageState createState() => _StravaFlutterPageState();
}

class _StravaFlutterPageState extends State<StravaFlutterPage> {
  final TextEditingController _textEditingController = TextEditingController();
  final DateFormat dateFormatter = DateFormat("HH:mm:ss");
  late final StravaClient stravaClient;

  bool isLoggedIn = false;
  TokenResponse? token;

  @override
  void initState() {
    super.initState();
    stravaClient = StravaClient(secret: secret, clientId: clientId);
  }

  FutureOr<void> showErrorMessage(dynamic error, dynamic stackTrace) async {
    if (error is Fault) {
      await showDialog(
        context: context,
        builder: (context) => AlertDialog(
          title: Text("Did Receive Fault"),
          content: Text(
            "Message: ${error.message}\n-----------------\nErrors:\n${(error.errors ?? []).map((e) => "Code: ${e.code}\nResource: ${e.resource}\nField: ${e.field}\n").join("\n----------\n")}",
          ),
        ),
      );
    }
  }

  void testAuthentication() {
    ExampleAuthentication(stravaClient).testAuthentication(
      [
        AuthenticationScope.profile_read_all,
        AuthenticationScope.read_all,
        AuthenticationScope.activity_read_all
      ],
      "stravaflutter://redirect",
    ).then((token) {
      setState(() {
        isLoggedIn = true;
        this.token = token;
      });
      _textEditingController.text = token.accessToken;
    }).catchError(showErrorMessage);
  }

  void testDeauth() {
    ExampleAuthentication(stravaClient).testDeauthorize().then((value) {
      setState(() {
        isLoggedIn = false;
        this.token = null;
        _textEditingController.clear();
      });
    }).catchError(showErrorMessage);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Flutter Strava Plugin"),
        actions: [
          Icon(
            Icons.radio_button_checked_outlined,
            color: isLoggedIn ? Colors.white : Colors.red,
          ),
          SizedBox(width: 8,)
        ],
      ),
      body: Container(
        padding: const EdgeInsets.symmetric(horizontal: 16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [_login(), _apiGroups()],
        ),
      ),
    );
  }

  Widget _login() {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            ElevatedButton(
              child: Text("Login With Strava"),
              onPressed: testAuthentication,
            ),
            ElevatedButton(
              child: Text("De Authorize"),
              onPressed: testDeauth,
            )
          ],
        ),
        SizedBox(height: 8,),
        TextField(
          minLines: 1,
          maxLines: 3,
          controller: _textEditingController,
          decoration: InputDecoration(
            border: OutlineInputBorder(),
            label: Text("Access Token"),
            suffixIcon: TextButton(
              child: Text("Copy"),
              onPressed: () {
                Clipboard.setData(ClipboardData(text: _textEditingController.text))
                  .then((value) => ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Copied!"))));
              },
            ),
          ),
        ),
        Divider()
      ],
    );
  }

  Widget _apiGroups() {
    return IgnorePointer(
      ignoring: !isLoggedIn,
      child: AnimatedOpacity(
        opacity: isLoggedIn ? 1.0 : 0.4,
        duration: Duration(milliseconds: 200),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            ListTile(title: Text("Athletes"), trailing: Icon(Icons.chevron_right),),
            ListTile(title: Text("Clubs"), trailing: Icon(Icons.chevron_right),),
            ListTile(title: Text("Gears"), trailing: Icon(Icons.chevron_right),),
            ListTile(title: Text("Routes"), trailing: Icon(Icons.chevron_right),),
            ListTile(title: Text("Running Races"), trailing: Icon(Icons.chevron_right),),
            ListTile(title: Text("Segment Efforts"), trailing: Icon(Icons.chevron_right),),
            ListTile(title: Text("Segments"), trailing: Icon(Icons.chevron_right),),
            ListTile(title: Text("Streams"), trailing: Icon(Icons.chevron_right),),
            ListTile(title: Text("Uploads"), trailing: Icon(Icons.chevron_right),)
          ],
        ),
      ),
    );
  }
}

以上就是关于strava_flutter插件的基本介绍及其在Flutter项目中的使用方法。希望这对您有所帮助!如果您有任何问题或需要实现其他API功能,请随时提出新问题。


更多关于Flutter Strava API集成插件strava_client的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter Strava API集成插件strava_client的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中集成并使用strava_client插件来与Strava API进行交互的代码示例。这个示例将展示如何初始化插件、获取用户授权以及调用Strava API获取活动列表。

首先,确保你已经在pubspec.yaml文件中添加了strava_client依赖:

dependencies:
  flutter:
    sdk: flutter
  strava_client: ^最新版本号  # 替换为实际可用的最新版本号

然后,运行flutter pub get来安装依赖。

接下来,在你的Flutter项目中,你需要进行以下步骤:

  1. 配置Strava API客户端

在你的android/app/src/main/AndroidManifest.xml文件中,确保你有必要的互联网权限:

<uses-permission android:name="android.permission.INTERNET" />

在你的ios/Runner/Info.plist文件中,你可能需要配置一些额外的权限或设置,具体取决于你的应用需求。

  1. 初始化Strava客户端

在你的Flutter项目的lib目录下,创建一个新的Dart文件(例如strava_service.dart),并在其中初始化Strava客户端:

import 'package:flutter/material.dart';
import 'package:strava_client/strava_client.dart';

class StravaService {
  late StravaClient _stravaClient;

  StravaService(String clientId, String clientSecret, String redirectUri) {
    _stravaClient = StravaClient(
      clientId: clientId,
      clientSecret: clientSecret,
      redirectUri: redirectUri,
    );
  }

  // 获取用户授权URL
  Future<String> getAuthorizationUrl() async {
    return _stravaClient.getAuthorizationUrl();
  }

  // 使用授权码获取访问令牌
  Future<AccessToken> getAccessToken(String code) async {
    return await _stravaClient.getAccessToken(code);
  }

  // 获取用户活动列表
  Future<List<Activity>> getActivities(AccessToken accessToken) async {
    return await accessToken.activities.getAthleteActivities();
  }
}
  1. 在UI中使用Strava服务

在你的主Dart文件(例如main.dart)中,使用StravaService来管理Strava API的交互:

import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart'; // 用于打开浏览器
import 'strava_service.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late StravaService _stravaService;
  String? _authorizationUrl;
  List<Activity>? _activities;

  @override
  void initState() {
    super.initState();
    _stravaService = StravaService(
      clientId: '你的Strava客户端ID',
      clientSecret: '你的Strava客户端密钥',
      redirectUri: '你的重定向URI',
    );

    // 获取授权URL
    _getAuthorizationUrl();
  }

  Future<void> _getAuthorizationUrl() async {
    setState(() {
      _authorizationUrl = await _stravaService.getAuthorizationUrl();
    });
  }

  Future<void> _handleAuthorizationResponse(String code) async {
    try {
      AccessToken accessToken = await _stravaService.getAccessToken(code);
      _activities = await accessToken.activities.getAthleteActivities();
    } catch (e) {
      print('Error fetching access token: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Strava API Integration'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              if (_authorizationUrl != null)
                ElevatedButton(
                  onPressed: () async {
                    // 打开授权URL
                    if (await canLaunch(_authorizationUrl!)) {
                      await launch(_authorizationUrl!,
                          forceWebView: true,
                          webViewConfiguration: WebViewConfiguration(
                            javascriptMode: JavaScriptMode.unrestricted,
                          )
                      );

                      // 假设授权后重定向回你的应用,并附带授权码
                      // 在这里你需要处理重定向,并调用_handleAuthorizationResponse
                      // 这通常涉及设置一个URI监听器或深度链接处理
                      // 由于这是一个示例,我们直接模拟一个授权码
                      String fakeAuthorizationCode = '假设的授权码';
                      _handleAuthorizationResponse(fakeAuthorizationCode);
                    }
                  },
                  child: Text('获取授权'),
                ),
              if (_activities != null)
                ListView.builder(
                  shrinkWrap: true,
                  itemCount: _activities!.length,
                  itemBuilder: (context, index) {
                    Activity activity = _activities![index];
                    return ListTile(
                      title: Text('活动名称: ${activity.name}'),
                      subtitle: Text('活动日期: ${activity.startDateLocal}'),
                    );
                  },
                ),
            ],
          ),
        ),
      ),
    );
  }
}

注意

  • 在真实应用中,处理重定向和提取授权码的过程会更复杂。你可能需要设置URI监听器或使用深度链接来捕获重定向后的URL,并从中提取授权码。
  • 在这个示例中,我们直接使用了一个“假设的授权码”,这在实际应用中是不可行的。
  • 你需要确保在Strava开发者门户中正确配置了你的重定向URI,并且你的应用有权限访问所需的数据。
  • 由于url_launcher插件用于打开浏览器,你可能需要在pubspec.yaml文件中添加该依赖:url_launcher: ^最新版本号

希望这个示例能帮助你在Flutter项目中集成Strava API。

回到顶部